pax_global_header00006660000000000000000000000064141071751730014520gustar00rootroot0000000000000052 comment=d3de8e45e06a21d31cca0046ceb16ced1ef3563a sedutil-1.20.0/000077500000000000000000000000001410717517300132515ustar00rootroot00000000000000sedutil-1.20.0/.gitattributes000066400000000000000000000047261410717517300161550ustar00rootroot00000000000000############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain sedutil-1.20.0/.gitignore000066400000000000000000000053041410717517300152430ustar00rootroot00000000000000## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ build/ [Bb]in/ [Oo]bj/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile *.VC.db # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.Publish.xml # NuGet Packages Directory ## TODO: If you have NuGet Package Restore enabled, uncomment the next line #packages/ # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.[Pp]ublish.xml *.pfx *.publishsettings # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files App_Data/*.mdf App_Data/*.ldf #LightSwitch generated files GeneratedArtifacts/ _Pvt_Extensions/ ModelManifest.xml # ========================= # Windows detritus # ========================= # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac desktop service store files .DS_Store # Autotools Makefile.in /autom4te.cache /aclocal.m4 /compile /configure /depcomp /install-sh /missing /stamp-h1 config.h config.h.in config.status Makefile sedutil-*.tar.* linuxpba sedutil-cli # GCC .deps/ *.o .dirstamp # project specific files *.VC.opendb *.lnk /dist/ *.zip *.tgz Doxygen/ **/private/private.xml /images/*/* !/images/buildroot/ !/images/buildroot/* /LinuxPBA/dist/ /linux/CLI/dist/ # inno installer output windows/installer/Output/ # hacked exe files for different flavors windows/installer/exesedutil-1.20.0/.vscode/000077500000000000000000000000001410717517300146125ustar00rootroot00000000000000sedutil-1.20.0/.vscode/c_cpp_properties.json000066400000000000000000000005461410717517300210520ustar00rootroot00000000000000{ "configurations": [ { "name": "Linux", "includePath" : ["${workspaceFolder}/Common/**","${workspaceFolder}/linux/**","${workspaceFolder}/LinuxPBA/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "linux-gcc-x64" } ], "version": 4 } sedutil-1.20.0/.vscode/launch.json000066400000000000000000000017251410717517300167640ustar00rootroot00000000000000{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "sedutil_debug", "type": "cppdbg", "request": "launch", "program": "sedutil-cli", "args": ["--query","/dev/sda"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": false, "MIMode": "gdb", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true } ], "preLaunchTask": "sedutil_build", "miDebuggerPath": "/usr/bin/gdb" } ] }sedutil-1.20.0/.vscode/settings.json000066400000000000000000000001501410717517300173410ustar00rootroot00000000000000{ "editor.fontSize": 18, "editor.cursorStyle": "block", "editor.accessibilityPageSize": 18 }sedutil-1.20.0/.vscode/tasks.json000066400000000000000000000012571410717517300166370ustar00rootroot00000000000000{ "version": "2.0.0", "tasks": [ { "type": "shell", "label": "sedutil_build", "command": "make", "options": {"cwd": "${workspaceFolder}"}, "args": [ "V=0", "CFLAGS='-g -Og'", "CXXFLAGS='-g -Og'", "sedutil-cli" ], "problemMatcher": [ "$gcc" ], "group": { "kind": "build", "isDefault": true } }, { "type": "shell", "label": "clean ", "command": "make", "args": [ "clean" ], "problemMatcher": [ "$gcc" ], } ] } sedutil-1.20.0/BUILDING000066400000000000000000000005101410717517300143650ustar00rootroot00000000000000sedutil is built using autotools and make. steps: autoreconf -i ./configure --enable-silent-rules make ------------------------ This will also build the PBA ignore it. If you get an errot building that says Version.h is missing you need to make all. This is an issue with how autotools handles built sources and dependencies. sedutil-1.20.0/CONTRIBUTING000066400000000000000000000004731410717517300151070ustar00rootroot00000000000000Contributing to the Drive Trust Alliance sedutil project. We welcome contributions to the project but in order to maintain our ability to monitize this software we require that contributions are accompanied by a signed copy of the DTA_Contributor_Agreement_v2 included in this directory. Thanks for understandingsedutil-1.20.0/Common/000077500000000000000000000000001410717517300145015ustar00rootroot00000000000000sedutil-1.20.0/Common/Copyright.txt000066400000000000000000000015521410717517300172150ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ sedutil-1.20.0/Common/DtaAnnotatedDump.cpp000066400000000000000000000317431410717517300204110ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include #include #include #include "DtaDevEnterprise.h" #include "DtaHashPwd.h" #include "DtaEndianFixup.h" #include "DtaStructures.h" #include "DtaCommand.h" #include "DtaResponse.h" #include "DtaSession.h" #include "DtaHexDump.h" #include "DtaAnnotatedDump.h" using namespace std; //////////////////////////////////////////////////////////////////////////////// DtaToken::DtaToken(void) : //////////////////////////////////////////////////////////////////////////////// m_TokenType (NONE), m_HeaderLength (0), m_DataLength (0), m_TokenLength (0), m_token (NULL), m_data (NULL), m_value (0ULL), m_sign (false) { } //////////////////////////////////////////////////////////////////////////////// DtaToken::~DtaToken(void) //////////////////////////////////////////////////////////////////////////////// { } //////////////////////////////////////////////////////////////////////////////// void DtaToken::str2int(uint8_t * buf, bool byte) //////////////////////////////////////////////////////////////////////////////// { // user says it's a byte string, or it's so large it must be if (byte || m_DataLength > sizeof(m_value)) { m_data = buf; m_value = 0ULL; return; } // zero-sized ? if (m_DataLength == 0) { m_data = NULL; m_value = 0ULL; return; } // zero-extend 1B to 8B sized BE integer uint64_t V = 0; uint8_t * n = (uint8_t *) &V; memset(n, '\0', sizeof(V)); memcpy(n+(sizeof(V)-m_DataLength), buf, m_DataLength); // convert integer to host byte order V = SWAP64(V); // sign-extend if appropriate if (m_sign && (m_DataLength < sizeof(V))) { const int shift = 8 * (sizeof(V) - m_DataLength); int64_t v = V; v = v << shift; v = v >> shift; V = v; } // write out integer value m_data = NULL; m_value = V; } //////////////////////////////////////////////////////////////////////////////// void DtaToken::parse(uint8_t * buf, uint32_t buflen) //////////////////////////////////////////////////////////////////////////////// { LOG(D1) << "Entering DtaToken::parse " << buflen; m_token = buf; const CAtomHeader & atom = * (CAtomHeader *) buf; if (atom.TinyAtom.indicator == atom.TinyAtom.INDICATOR) { m_TokenType = TINY_ATOM; m_sign = atom.TinyAtom.sign; m_HeaderLength = atom.TinyAtom.HEADER_SIZE; m_DataLength = 0; m_TokenLength = atom.TinyAtom.HEADER_SIZE; m_data = NULL; if (m_sign) { m_value = int64_t(atom.TinyAtom_sign.value); } else { m_value = uint64_t(atom.TinyAtom.value); } } else if (atom.ShortAtom.indicator == atom.ShortAtom.INDICATOR) { m_TokenType = SHORT_ATOM; m_sign = atom.ShortAtom.sign; m_HeaderLength = atom.ShortAtom.HEADER_SIZE; m_DataLength = atom.ShortAtom.length; m_TokenLength = atom.ShortAtom.HEADER_SIZE + m_DataLength; str2int(m_token+atom.ShortAtom.HEADER_SIZE, atom.ShortAtom.byte); } else if (atom.MediumAtom.indicator == atom.MediumAtom.INDICATOR) { m_TokenType = MEDIUM_ATOM; m_sign = atom.MediumAtom.sign; m_HeaderLength = atom.MediumAtom.HEADER_SIZE; m_DataLength = uint32_t(atom.MediumAtom.length_msb) << 8 | uint32_t(atom.MediumAtom.length_lsb); m_TokenLength = atom.MediumAtom.HEADER_SIZE + m_DataLength; str2int(m_token+atom.MediumAtom.HEADER_SIZE, atom.MediumAtom.byte); } else if (atom.LongAtom.indicator == atom.LongAtom.INDICATOR) { m_TokenType = LONG_ATOM; m_sign = atom.LongAtom.sign; m_HeaderLength = atom.LongAtom.HEADER_SIZE; m_DataLength = (uint32_t(atom.LongAtom.length[0]) << 8 | uint32_t(atom.LongAtom.length[1])) << 8 | uint32_t(atom.LongAtom.length[2]); m_TokenLength = atom.LongAtom.HEADER_SIZE + m_DataLength; str2int(m_token+atom.LongAtom.HEADER_SIZE, atom.LongAtom.byte); } else { m_TokenType = TOKEN; m_sign = 0; m_HeaderLength = 1; m_DataLength = 0; m_TokenLength = 1; m_data = NULL; m_value = m_token[0]; } } //////////////////////////////////////////////////////////////////////////////// int DtaToken::print(FILE *stream, uint32_t buflen) //////////////////////////////////////////////////////////////////////////////// { int ret = 0; ret += fprintf(stream, "%u\t", m_TokenLength); // print out atom header unsigned int len = min(m_HeaderLength, buflen); ret += fprintf(stream, "("); for(unsigned int n=0; n 0) { buflen = 0; ret += ret2; } } for(unsigned int n=0; n>\n"); else if (cmd == IF_SEND) fprintf(stream, "<< IF_SEND >>\n"); else fprintf(stream, "<< 0x%2.2X\n >>\n", cmd); // echo header OPALHeader h; memcpy(&h, buffer, sizeof(h)); IFLOG(D1) { fprintf(stream, "ComPacket.extendedComID %2.2X%2.2X%2.2X%2.2X\n", h.cp.extendedComID[0], h.cp.extendedComID[1], h.cp.extendedComID[2], h.cp.extendedComID[3]); fprintf(stream, "ComPacket.outstandingData %8.8X\n", SWAP32(h.cp.outstandingData)); fprintf(stream, "ComPacket.minTransfer %8.8X\n", SWAP32(h.cp.minTransfer)); fprintf(stream, "ComPacket.length %8.8X\n", SWAP32(h.cp.length)); fprintf(stream, "Packet.TSN %8.8X\n", SWAP32(h.pkt.TSN)); fprintf(stream, "Packet.HSN %8.8X\n", SWAP32(h.pkt.HSN)); fprintf(stream, "Packet.seqNumber %8.8X\n", SWAP32(h.pkt.seqNumber)); fprintf(stream, "Packet.ackType %8.8X\n", SWAP16(h.pkt.ackType)); fprintf(stream, "Packet.acknowledgement %8.8X\n", SWAP32(h.pkt.acknowledgement)); fprintf(stream, "Packet.length %8.8X\n", SWAP32(h.pkt.length)); fprintf(stream, "DataSubPacket.kind %8.8X\n", SWAP16(h.subpkt.kind)); fprintf(stream, "DataSubPacket.length %8.8X\n", SWAP32(h.subpkt.length)); } const uint32_t buflen = SWAP32(h.subpkt.length); if (buflen > bufferlen) { fprintf(stream, "Overflow: h.subpkt.length = %u, bufferlen = %u\n", buflen, bufferlen); return 0xff; } // set up pointers to scan buffer unsigned char * p = (unsigned char *) buffer + sizeof(h); unsigned char * q = p + buflen; // scan buffer while(p < q) { DtaToken token; token.parse(p, (uint32_t)(q-p)); token.print(stream, (uint32_t)(q-p)); if (p + token.m_TokenLength > q) fprintf(stream, "(token truncated)"); p += token.m_TokenLength; } return 0; } sedutil-1.20.0/Common/DtaAnnotatedDump.h000066400000000000000000000075501410717517300200550ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma pack(push,1) typedef union CAtomHeader_t { // four bytes in big endian (network) byte order uint8_t all[4]; // TINY ATOM class CTinyAtom { public: enum { INDICATOR = 0, // 0b HEADER_SIZE = 1, }; unsigned value : 6; unsigned sign : 1; unsigned indicator : 1; } TinyAtom; // TINY ATOM (sign) class CTinyAtom_sign { public: enum { INDICATOR = 0, // 0b HEADER_SIZE = 1, }; signed value : 6; unsigned sign : 1; unsigned indicator : 1; } TinyAtom_sign; // SHORT ATOM class CShortAtom { public: enum { INDICATOR = 2, // 10b HEADER_SIZE = 1, }; unsigned length : 4; unsigned sign : 1; unsigned byte : 1; unsigned indicator : 2; } ShortAtom; // MEDIUM ATOM class CMediumAtom { public: enum { INDICATOR = 6, // 110b HEADER_SIZE = 2, }; unsigned length_msb : 3; unsigned sign : 1; unsigned byte : 1; unsigned indicator : 3; uint8_t length_lsb; } MediumAtom; // LONG ATOM class CLongAtom { public: enum { INDICATOR = 14, // 1110b HEADER_SIZE = 4, }; unsigned sign : 1; unsigned byte : 1; unsigned reserved : 2; unsigned indicator : 4; uint8_t length[3]; } LongAtom; } CAtomHeader; #pragma pack(pop) //////////////////////////////////////////////////////////////////////////////// class DtaToken //////////////////////////////////////////////////////////////////////////////// { public: DtaToken(void); ~DtaToken(void); void parse(uint8_t * buf, uint32_t buflen); int print(FILE *stream, uint32_t buflen); typedef enum _TokenType { NONE, TINY_ATOM, SHORT_ATOM, MEDIUM_ATOM, LONG_ATOM, TOKEN, } TokenType; TokenType m_TokenType; uint32_t m_HeaderLength; uint32_t m_DataLength; uint32_t m_TokenLength; uint8_t * m_token; uint8_t * m_data; uint64_t m_value; bool m_sign; private: void str2int(uint8_t * buf, bool byte); int printTokenType(FILE *stream, uint8_t token); int printAscii(FILE *stream, uint8_t * buf, uint32_t buflen); int printUID(FILE *stream, uint8_t buf[8]); }; //////////////////////////////////////////////////////////////////////////////// extern uint8_t DtaAnnotatedDump(ATACOMMAND cmd, void * buffer, uint32_t bufferlen); //////////////////////////////////////////////////////////////////////////////// sedutil-1.20.0/Common/DtaCommand.cpp000066400000000000000000000176351410717517300172300ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include "DtaCommand.h" #include "DtaEndianFixup.h" #include "DtaHexDump.h" #include "DtaStructures.h" using namespace std; DtaCommand::DtaCommand() { LOG(D1) << "Creating DtaCommand()"; cmdbuf = commandbuffer + IO_BUFFER_ALIGNMENT; cmdbuf = (uint8_t*)((uintptr_t)cmdbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); respbuf = responsebuffer + IO_BUFFER_ALIGNMENT; respbuf = (uint8_t*)((uintptr_t)respbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); } /* Fill in the header information and format the call */ DtaCommand::DtaCommand(OPAL_UID InvokingUid, OPAL_METHOD method) { LOG(D1) << "Creating DtaCommand(ID, InvokingUid, method)"; cmdbuf = commandbuffer + IO_BUFFER_ALIGNMENT; cmdbuf = (uint8_t*)((uintptr_t)cmdbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); respbuf = responsebuffer + IO_BUFFER_ALIGNMENT; respbuf = (uint8_t*)((uintptr_t)respbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); reset(InvokingUid, method); } void DtaCommand::reset() { LOG(D1) << "Entering DtaCommand::reset()"; memset(cmdbuf, 0, MAX_BUFFER_LENGTH); memset(respbuf, 0, MIN_BUFFER_LENGTH); bufferpos = sizeof (OPALHeader); } void DtaCommand::reset(OPAL_UID InvokingUid, vector method){ LOG(D1) << "Entering DtaCommand::reset(OPAL_UID,uint8_t)"; reset(); cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; addToken(InvokingUid); addToken(method); } void DtaCommand::reset(vector InvokingUid, vector method){ LOG(D1) << "Entering DtaCommand::reset(uint8_t,uint8_t)"; reset(); cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; addToken(InvokingUid); addToken(method); } void DtaCommand::reset(OPAL_UID InvokingUid, OPAL_METHOD method) { LOG(D1) << "Entering DtaCommand::reset(OPAL_UID, OPAL_METHOD)"; reset(); cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; addToken(InvokingUid); cmdbuf[bufferpos++] = OPAL_SHORT_ATOM::BYTESTRING8; memcpy(&cmdbuf[bufferpos], &OPALMETHOD[method][0], 8); /* bytes 11-18 */ bufferpos += 8; } void DtaCommand::addToken(uint64_t number) { int startat = 0; LOG(D1) << "Entering DtaCommand::addToken(uint64_t)"; if (number < 64) { cmdbuf[bufferpos++] = (uint8_t) number & 0x000000000000003f; } else { if (number < 0x100) { cmdbuf[bufferpos++] = 0x81; startat = 0; } else if (number < 0x10000) { cmdbuf[bufferpos++] = 0x82; startat = 1; } else if (number < 0x100000000) { cmdbuf[bufferpos++] = 0x84; startat = 3; } else { cmdbuf[bufferpos++] = 0x88; startat = 7; } for (int i = startat; i > -1; i--) { cmdbuf[bufferpos++] = (uint8_t) ((number >> (i * 8)) & 0x00000000000000ff); } } } void DtaCommand::addToken(vector token) { LOG(D1) << "Entering addToken(vector)"; for (uint32_t i = 0; i < token.size(); i++) { cmdbuf[bufferpos++] = token[i]; } } void DtaCommand::addToken(const char * bytestring) { LOG(D1) << "Entering DtaCommand::addToken(const char * )"; uint16_t length = (uint16_t) strlen(bytestring); if (length == 0) { /* null token e.g. default password */ cmdbuf[bufferpos++] = (uint8_t)0xa1; cmdbuf[bufferpos++] = (uint8_t)0x00; } else if (length < 16) { /* use tiny atom */ cmdbuf[bufferpos++] = (uint8_t) length | 0xa0; } else if (length < 2048) { /* Use Medium Atom */ cmdbuf[bufferpos++] = 0xd0 | (uint8_t) ((length >> 8) & 0x07); cmdbuf[bufferpos++] = (uint8_t) (length & 0x00ff); } else { /* Use Large Atom */ LOG(E) << "FAIL -- can't send LARGE ATOM size bytestring in 2048 Packet"; exit(EXIT_FAILURE); } memcpy(&cmdbuf[bufferpos], bytestring, length); bufferpos += length; } void DtaCommand::addToken(OPAL_TOKEN token) { LOG(D1) << "Entering DtaCommand::addToken(OPAL_TOKEN)"; cmdbuf[bufferpos++] = (uint8_t) token; } void DtaCommand::addToken(OPAL_SHORT_ATOM token) { LOG(D1) << "Entering DtaCommand::addToken(OPAL_SHORT_ATOM)"; cmdbuf[bufferpos++] = (uint8_t)token; } void DtaCommand::addToken(OPAL_TINY_ATOM token) { LOG(D1) << "Entering DtaCommand::addToken(OPAL_TINY_ATOM)"; cmdbuf[bufferpos++] = (uint8_t) token; } void DtaCommand::addToken(OPAL_UID token) { LOG(D1) << "Entering DtaCommand::addToken(OPAL_UID)"; cmdbuf[bufferpos++] = OPAL_SHORT_ATOM::BYTESTRING8; memcpy(&cmdbuf[bufferpos], &OPALUID[token][0], 8); bufferpos += 8; } void DtaCommand::complete(uint8_t EOD) { LOG(D1) << "Entering DtaCommand::complete(uint8_t EOD)"; if (EOD) { cmdbuf[bufferpos++] = OPAL_TOKEN::ENDOFDATA; cmdbuf[bufferpos++] = OPAL_TOKEN::STARTLIST; cmdbuf[bufferpos++] = 0x00; cmdbuf[bufferpos++] = 0x00; cmdbuf[bufferpos++] = 0x00; cmdbuf[bufferpos++] = OPAL_TOKEN::ENDLIST; } /* fill in the lengths and add the modulo 4 padding */ OPALHeader * hdr; hdr = (OPALHeader *) cmdbuf; hdr->subpkt.length = SWAP32(bufferpos - (sizeof (OPALHeader))); while (bufferpos % 4 != 0) { cmdbuf[bufferpos++] = 0x00; } hdr->pkt.length = SWAP32((bufferpos - sizeof (OPALComPacket)) - sizeof (OPALPacket)); hdr->cp.length = SWAP32(bufferpos - sizeof (OPALComPacket)); if (bufferpos > MAX_BUFFER_LENGTH) { LOG(D1) << " Standard Buffer Overrun " << bufferpos; exit(EXIT_FAILURE); } } void DtaCommand::changeInvokingUid(std::vector Invoker) { LOG(D1) << "Entering DtaCommand::changeInvokingUid()"; int offset = sizeof (OPALHeader) + 1; /* bytes 2-9 */ for (uint32_t i = 0; i < Invoker.size(); i++) { cmdbuf[offset + i] = Invoker[i]; } } void * DtaCommand::getCmdBuffer() { return cmdbuf; } void * DtaCommand::getRespBuffer() { return respbuf; } void DtaCommand::dumpCommand() { OPALHeader * hdr = (OPALHeader *)cmdbuf; DtaHexDump(cmdbuf, SWAP32(hdr->cp.length) + sizeof(OPALComPacket)); } void DtaCommand::dumpResponse() { OPALHeader *hdr = (OPALHeader *)respbuf; DtaHexDump(respbuf, SWAP32(hdr->cp.length) + sizeof(OPALComPacket)); } uint16_t DtaCommand::outputBufferSize() { // if (MIN_BUFFER_LENGTH + 1 > bufferpos) return(MIN_BUFFER_LENGTH); if(bufferpos % 512) return(((uint16_t)(bufferpos / 512) + 1) * 512); else return((uint16_t)(bufferpos / 512) * 512); } void DtaCommand::setcomID(uint16_t comID) { OPALHeader * hdr; hdr = (OPALHeader *) cmdbuf; LOG(D1) << "Entering DtaCommand::setcomID()"; hdr->cp.extendedComID[0] = ((comID & 0xff00) >> 8); hdr->cp.extendedComID[1] = (comID & 0x00ff); hdr->cp.extendedComID[2] = 0x00; hdr->cp.extendedComID[3] = 0x00; } void DtaCommand::setTSN(uint32_t TSN) { LOG(D1) << "Entering DtaCommand::setTSN()"; OPALHeader * hdr; hdr = (OPALHeader *) cmdbuf; hdr->pkt.TSN = TSN; } void DtaCommand::setHSN(uint32_t HSN) { LOG(D1) << "Entering DtaCommand::setHSN()"; OPALHeader * hdr; hdr = (OPALHeader *) cmdbuf; hdr->pkt.HSN = HSN; } DtaCommand::~DtaCommand() { LOG(D1) << "Destroying DtaCommand"; } sedutil-1.20.0/Common/DtaCommand.h000066400000000000000000000136301410717517300166640ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include #include "DtaLexicon.h" class DtaDevOpal; class DtaDevEnterprise; using namespace std; /** A class to build & send Opal Command streams to a TPer. * This class attempts to closely mimic the command * pseudo code used in the TCG documents, the syntactic * sugar is not represented. See TCG document Storage Architecture * Core Specification R2.00 V2.00 Section 3.2.1.2 for all * the gory details. * * @see DtaLexicon.h for structs, typedefs and enums used to encode * the bytestream. */ class DtaCommand { friend class DtaDevOpal; friend class DtaDevEnterprise; public: /** Default constructor, allocates the command and resonse buffers. */ DtaCommand(); /** Constructor that initializes the incokingUid and method fields. * @param InvokingUid The UID used to call the SSC method * @param method The SSC method to be called */ DtaCommand(OPAL_UID InvokingUid, OPAL_METHOD method); /** destructor frees the command and response buffers */ ~DtaCommand(); /** Add a Token to the bytstream of type OPAL_TOKEN. */ void addToken(OPAL_TOKEN token); /** Add a Token to the bytstream of type OPL_SHORT ATOM. */ void addToken(OPAL_SHORT_ATOM token); /** Add a Token to the bytstream of type OPL_TINY ATOM. */ void addToken(OPAL_TINY_ATOM token); /** Add a Token to the bytstream of from the OPALUID array. */ void addToken(OPAL_UID token); /** Add a Token to the bytstream of type c-string */ void addToken(const char * bytestring); /** Add a Token to the bytstream of type vector. * This token must be a complete token properly encoded * with the proper TCG bytestream header information */ void addToken(std::vector token); /** Add a Token to the bytstream of type uint64. */ void addToken(uint64_t number); /** Set the commid to be used in the command. */ void setcomID(uint16_t comID); /** set the Host session number to be used in the command. */ void setHSN(uint32_t HSN); /** Set the TPer session number to be used for the command. */ void setTSN(uint32_t TSN); /** Add the required fields to the end of the bytestream. If EOD is true (default) the * EOD token and the method status list will be added to the end of the bytestream. * Then the bytstram is padded to a 4-byte boundary if required and the length fields * are populated in packet, subpacket and command packet. * * @param EOD a bool to signal that command requires the EOD and method status fields */ void complete(uint8_t EOD = 1); /** Clears the command buffer and resets the the end of buffer pointer * @see bufferpos */ void reset(); /** Clears the command buffer and resets the the end of buffer pointer * also initializes the invoker and method fields. * * @param InvokingUid The UID used to call the SSC method * @param method The SSC method to be called */ void reset(OPAL_UID InvokingUid, OPAL_METHOD method); /** Clears the command buffer and resets the the end of buffer pointer * also initializes the invoker and method fields. * The invoker is passed as a vector this is used for the case * where the invoker is not an OPAL user, typically a table. * * @param InvokingUid The UID used to call the SSC method * @param method The SSC method to be called */ void reset(OPAL_UID InvokingUid, vector method); /** Clears the command buffer and resets the the end of buffer pointer * also initializes the invoker and method fields. * Both the invoker and method are passed as a vector * * @param InvokingUid The UID used to call the SSC method * @param method The SSC method to be called */ void reset(vector InvokingUid, vector method); /** Changes the invoker field. * The invoker is passed as a vector this is used for the case * where the invoker is not an OPAL user, typically a table. * * @param Invoker The UID used to call the SSC method */ void changeInvokingUid(vector Invoker); /** Produce a hexdump of the response. Typically used in debugging and tracing */ void dumpResponse(); /** Produce a hexdump of the command. Typically used in debugging and tracing */ void dumpCommand(); /** Return the space used in the command buffer (rounded to 512 bytes) */ uint16_t outputBufferSize(); private: /** return a pointer to the command buffer */ void * getCmdBuffer(); /** return a pointer to the response buffer. */ void * getRespBuffer(); uint8_t commandbuffer[MAX_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; /**< buffer allocation allow for 1k alignment */ uint8_t responsebuffer[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; /**< buffer allocation allow for 1k alignment */ uint8_t *cmdbuf; /**< Pointer to the command buffer */ uint8_t *respbuf; /**< pointer to the response buffer */ uint32_t bufferpos = 0; /**< position of the next byte in the command buffer */ }; sedutil-1.20.0/Common/DtaConstants.h000066400000000000000000000040731410717517300172630ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ /** MAX Length of input the IO buffers used */ #define MAX_BUFFER_LENGTH 61440 /** Length of input the IO buffers used */ #define MIN_BUFFER_LENGTH 2048 /** Alignment of the IO buffers. * generic align on 1k boundary probably not needed * but when things weren't working this was one of the * things I tried to make it work. */ #define IO_BUFFER_ALIGNMENT 1024 /** maximum number of disks to be scanned */ #define MAX_DISKS 20 /** iomanip commands to hexdump a field */ #define HEXON(x) "0x" << std::hex << std::setw(x) << std::setfill('0') /** iomanip command to return to standard ascii output */ #define HEXOFF std::dec << std::setw(0) << std::setfill(' ') /** Return Codes */ #define DTAERROR_UNSUPORTED_LOCKING_RANGE 0x81 #define DTAERROR_OBJECT_CREATE_FAILED 0x82 #define DTAERROR_INVALID_PARAMETER 0x83 #define DTAERROR_OPEN_ERR 0x84 #define DTAERROR_INVALID_LIFECYCLE 0x85 #define DTAERROR_INVALID_COMMAND 0x86 #define DTAERROR_AUTH_FAILED 0x87 #define DTAERROR_COMMAND_ERROR 0x88 #define DTAERROR_NO_METHOD_STATUS 0x89 #define DTAERROR_NO_LOCKING_INFO 0x8a /** Locking Range Configurations */ #define DTA_DISABLELOCKING 0x00 #define DTA_READLOCKINGENABLED 0x01 #define DTA_WRITELOCKINGENABLED 0x02 sedutil-1.20.0/Common/DtaDev.cpp000066400000000000000000000301371410717517300163600ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ /** Base device class. * An OS port must create a subclass of this class * implementing sendcmd, osmsSleep and identify * specific to the IO requirements of that OS */ #include "os.h" #include #include #include #include "DtaOptions.h" #include "DtaDev.h" #include "DtaStructures.h" #include "DtaConstants.h" #include "DtaEndianFixup.h" #include "DtaHexDump.h" using namespace std; /** Device Class (Base) represents a single disk device. * This is the functionality that is common to all OS's and SSC's */ DtaDev::DtaDev() { } DtaDev::~DtaDev() { } uint8_t DtaDev::isOpal2() { LOG(D1) << "Entering DtaDev::isOpal2 " << (uint16_t) disk_info.OPAL20; return disk_info.OPAL20; } uint8_t DtaDev::isOpal1() { LOG(D1) << "Entering DtaDev::isOpal1() " << (uint16_t)disk_info.OPAL10; return disk_info.OPAL10; } uint8_t DtaDev::isEprise() { LOG(D1) << "Entering DtaDev::isEprise " << (uint16_t) disk_info.Enterprise; return disk_info.Enterprise; } uint8_t DtaDev::isAnySSC() { LOG(D1) << "Entering DtaDev::isAnySSC " << (uint16_t)disk_info.ANY_OPAL_SSC; return disk_info.ANY_OPAL_SSC; } uint8_t DtaDev::isPresent() { LOG(D1) << "Entering DtaDev::isPresent() " << (uint16_t) isOpen; return isOpen; } uint8_t DtaDev::MBREnabled() { LOG(D1) << "Entering DtaDev::MBRENabled" << (uint16_t)disk_info.Locking_MBREnabled; return disk_info.Locking_MBREnabled; } uint8_t DtaDev::MBRDone() { LOG(D1) << "Entering DtaDev::MBRDone" << (uint16_t)disk_info.Locking_MBRDone; return disk_info.Locking_MBRDone; } uint8_t DtaDev::Locked() { LOG(D1) << "Entering DtaDev::Locked" << (uint16_t)disk_info.Locking_locked; return disk_info.Locking_locked; } uint8_t DtaDev::LockingEnabled() { LOG(D1) << "Entering DtaDev::LockingEnabled" << (uint16_t)disk_info.Locking_lockingEnabled; return disk_info.Locking_lockingEnabled; } char *DtaDev::getFirmwareRev() { return (char *)&disk_info.firmwareRev; } char *DtaDev::getModelNum() { return (char *)&disk_info.modelNum; } char *DtaDev::getSerialNum() { return (char *)&disk_info.serialNum; } DTA_DEVICE_TYPE DtaDev::getDevType() { return disk_info.devType; } void DtaDev::discovery0() { LOG(D1) << "Entering DtaDev::discovery0()"; uint8_t lastRC; void * d0Response = NULL; uint8_t * epos, *cpos; Discovery0Header * hdr; Discovery0Features * body; d0Response = discovery0buffer + IO_BUFFER_ALIGNMENT; d0Response = (void *)((uintptr_t)d0Response & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); memset(d0Response, 0, MIN_BUFFER_LENGTH); if ((lastRC = sendCmd(IF_RECV, 0x01, 0x0001, d0Response, MIN_BUFFER_LENGTH)) != 0) { LOG(D) << "Send D0 request to device failed " << (uint16_t)lastRC; return; } epos = cpos = (uint8_t *) d0Response; hdr = (Discovery0Header *) d0Response; LOG(D3) << "Dumping D0Response"; IFLOG(D3) DtaHexDump(hdr, SWAP32(hdr->length)); epos = epos + SWAP32(hdr->length); cpos = cpos + 48; // TODO: check header version do { body = (Discovery0Features *) cpos; switch (SWAP16(body->TPer.featureCode)) { /* could use of the structures here is a common field */ case FC_TPER: /* TPer */ disk_info.TPer = 1; disk_info.TPer_ACKNACK = body->TPer.acknack; disk_info.TPer_async = body->TPer.async; disk_info.TPer_bufferMgt = body->TPer.bufferManagement; disk_info.TPer_comIDMgt = body->TPer.comIDManagement; disk_info.TPer_streaming = body->TPer.streaming; disk_info.TPer_sync = body->TPer.sync; break; case FC_LOCKING: /* Locking*/ disk_info.Locking = 1; disk_info.Locking_locked = body->locking.locked; disk_info.Locking_lockingEnabled = body->locking.lockingEnabled; disk_info.Locking_lockingSupported = body->locking.lockingSupported; disk_info.Locking_MBRDone = body->locking.MBRDone; disk_info.Locking_MBREnabled = body->locking.MBREnabled; disk_info.Locking_mediaEncrypt = body->locking.mediaEncryption; break; case FC_GEOMETRY: /* Geometry Features */ disk_info.Geometry = 1; disk_info.Geometry_align = body->geometry.align; disk_info.Geometry_alignmentGranularity = SWAP64(body->geometry.alignmentGranularity); disk_info.Geometry_logicalBlockSize = SWAP32(body->geometry.logicalBlockSize); disk_info.Geometry_lowestAlignedLBA = SWAP64(body->geometry.lowestAlighedLBA); break; case FC_ENTERPRISE: /* Enterprise SSC */ disk_info.Enterprise = 1; disk_info.ANY_OPAL_SSC = 1; disk_info.Enterprise_rangeCrossing = body->enterpriseSSC.rangeCrossing; disk_info.Enterprise_basecomID = SWAP16(body->enterpriseSSC.baseComID); disk_info.Enterprise_numcomID = SWAP16(body->enterpriseSSC.numberComIDs); break; case FC_OPALV100: /* Opal V1 */ disk_info.OPAL10 = 1; disk_info.ANY_OPAL_SSC = 1; disk_info.OPAL10_basecomID = SWAP16(body->opalv100.baseComID); disk_info.OPAL10_numcomIDs = SWAP16(body->opalv100.numberComIDs); break; case FC_SINGLEUSER: /* Single User Mode */ disk_info.SingleUser = 1; disk_info.SingleUser_all = body->singleUserMode.all; disk_info.SingleUser_any = body->singleUserMode.any; disk_info.SingleUser_policy = body->singleUserMode.policy; disk_info.SingleUser_lockingObjects = SWAP32(body->singleUserMode.numberLockingObjects); break; case FC_DATASTORE: /* Datastore Tables */ disk_info.DataStore = 1; disk_info.DataStore_maxTables = SWAP16(body->datastore.maxTables); disk_info.DataStore_maxTableSize = SWAP32(body->datastore.maxSizeTables); disk_info.DataStore_alignment = SWAP32(body->datastore.tableSizeAlignment); break; case FC_OPALV200: /* OPAL V200 */ disk_info.OPAL20 = 1; disk_info.ANY_OPAL_SSC = 1; disk_info.OPAL20_basecomID = SWAP16(body->opalv200.baseCommID); disk_info.OPAL20_initialPIN = body->opalv200.initialPIN; disk_info.OPAL20_revertedPIN = body->opalv200.revertedPIN; disk_info.OPAL20_numcomIDs = SWAP16(body->opalv200.numCommIDs); disk_info.OPAL20_numAdmins = SWAP16(body->opalv200.numlockingAdminAuth); disk_info.OPAL20_numUsers = SWAP16(body->opalv200.numlockingUserAuth); disk_info.OPAL20_rangeCrossing = body->opalv200.rangeCrossing; break; default: if (0xbfff < (SWAP16(body->TPer.featureCode))) { // silently ignore vendor specific segments as there is no public doc on them disk_info.VendorSpecific += 1; } else { disk_info.Unknown += 1; LOG(D) << "Unknown Feature in Discovery 0 response " << std::hex << SWAP16(body->TPer.featureCode) << std::dec; /* should do something here */ } break; } cpos = cpos + (body->TPer.length + 4); } while (cpos < epos); } void DtaDev::puke() { LOG(D1) << "Entering DtaDev::puke()"; /* IDENTIFY */ cout << endl << dev << (disk_info.devType == DEVICE_TYPE_ATA ? " ATA " : disk_info.devType == DEVICE_TYPE_SAS ? " SAS " : disk_info.devType == DEVICE_TYPE_USB ? " USB " : disk_info.devType == DEVICE_TYPE_NVME ? " NVMe " : " OTHER "); cout << disk_info.modelNum << " " << disk_info.firmwareRev << " " << disk_info.serialNum << endl; /* TPer */ if (disk_info.TPer) { cout << "TPer function (" << HEXON(4) << FC_TPER << HEXOFF << ")" << std::endl; cout << " ACKNAK = " << (disk_info.TPer_ACKNACK ? "Y, " : "N, ") << "ASYNC = " << (disk_info.TPer_async ? "Y, " : "N. ") << "BufferManagement = " << (disk_info.TPer_bufferMgt ? "Y, " : "N, ") << "comIDManagement = " << (disk_info.TPer_comIDMgt ? "Y, " : "N, ") << "Streaming = " << (disk_info.TPer_streaming ? "Y, " : "N, ") << "SYNC = " << (disk_info.TPer_sync ? "Y" : "N") << std::endl; } if (disk_info.Locking) { cout << "Locking function (" << HEXON(4) << FC_LOCKING << HEXOFF << ")" << std::endl; cout << " Locked = " << (disk_info.Locking_locked ? "Y, " : "N, ") << "LockingEnabled = " << (disk_info.Locking_lockingEnabled ? "Y, " : "N, ") << "LockingSupported = " << (disk_info.Locking_lockingSupported ? "Y, " : "N, "); cout << "MBRDone = " << (disk_info.Locking_MBRDone ? "Y, " : "N, ") << "MBREnabled = " << (disk_info.Locking_MBREnabled ? "Y, " : "N, ") << "MediaEncrypt = " << (disk_info.Locking_mediaEncrypt ? "Y" : "N") << std::endl; } if (disk_info.Geometry) { cout << "Geometry function (" << HEXON(4) << FC_GEOMETRY << HEXOFF << ")" << std::endl; cout << " Align = " << (disk_info.Geometry_align ? "Y, " : "N, ") << "Alignment Granularity = " << disk_info.Geometry_alignmentGranularity << " (" << // display bytes (disk_info.Geometry_alignmentGranularity * disk_info.Geometry_logicalBlockSize) << ")" << ", Logical Block size = " << disk_info.Geometry_logicalBlockSize << ", Lowest Aligned LBA = " << disk_info.Geometry_lowestAlignedLBA << std::endl; } if (disk_info.Enterprise) { cout << "Enterprise function (" << HEXON(4) << FC_ENTERPRISE << HEXOFF << ")" << std::endl; cout << " Range crossing = " << (disk_info.Enterprise_rangeCrossing ? "Y, " : "N, ") << "Base comID = " << HEXON(4) << disk_info.Enterprise_basecomID << ", comIDs = " << disk_info.Enterprise_numcomID << HEXOFF << std::endl; } if (disk_info.OPAL10) { cout << "Opal V1.0 function (" << HEXON(4) << FC_OPALV100 << HEXOFF << ")" << std::endl; cout << "Base comID = " << HEXON(4) << disk_info.OPAL10_basecomID << HEXOFF << ", comIDs = " << disk_info.OPAL10_numcomIDs << std::endl; } if (disk_info.SingleUser) { cout << "SingleUser function (" << HEXON(4) << FC_SINGLEUSER << HEXOFF << ")" << std::endl; cout << " ALL = " << (disk_info.SingleUser_all ? "Y, " : "N, ") << "ANY = " << (disk_info.SingleUser_any ? "Y, " : "N, ") << "Policy = " << (disk_info.SingleUser_policy ? "Y, " : "N, ") << "Locking Objects = " << (disk_info.SingleUser_lockingObjects) << std::endl; } if (disk_info.DataStore) { cout << "DataStore function (" << HEXON(4) << FC_DATASTORE << HEXOFF << ")" << std::endl; cout << " Max Tables = " << disk_info.DataStore_maxTables << ", Max Size Tables = " << disk_info.DataStore_maxTableSize << ", Table size alignment = " << disk_info.DataStore_alignment << std::endl; } if (disk_info.OPAL20) { cout << "OPAL 2.0 function (" << HEXON(4) << FC_OPALV200 << ")" << HEXOFF << std::endl; cout << " Base comID = " << HEXON(4) << disk_info.OPAL20_basecomID << HEXOFF; cout << ", Initial PIN = " << HEXON(2) << static_cast(disk_info.OPAL20_initialPIN) << HEXOFF; cout << ", Reverted PIN = " << HEXON(2) << static_cast(disk_info.OPAL20_revertedPIN) << HEXOFF; cout << ", comIDs = " << disk_info.OPAL20_numcomIDs; cout << std::endl; cout << " Locking Admins = " << disk_info.OPAL20_numAdmins; cout << ", Locking Users = " << disk_info.OPAL20_numUsers; cout << ", Range Crossing = " << (disk_info.OPAL20_rangeCrossing ? "Y" : "N"); cout << std::endl; } if (disk_info.Unknown) cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl; } sedutil-1.20.0/Common/DtaDev.h000066400000000000000000000324161410717517300160270ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include "DtaStructures.h" #include "DtaLexicon.h" #include #include "DtaOptions.h" #include "DtaResponse.h" class DtaCommand; class DtaSession; using namespace std; /** Base class for a disk device. * This is a virtual base class defining the minimum functionality of device * object. The methods defined here are called by other parts of the program * so must be present in all devices */ class DtaDev { public: /** Default constructor, does nothing */ DtaDev(); /** Default destructor, does nothing*/ virtual ~DtaDev(); /** Does the device conform to the OPAL 2.0 SSC */ uint8_t isOpal2(); /** Does the device conform to the OPAL 1.0 SSC */ uint8_t isOpal1(); /** Does the device conform to the OPAL Enterprise SSC */ uint8_t isEprise(); /** Does the device conform to ANY TCG storage SSC */ uint8_t isAnySSC(); /** Is the MBREnabled flag set */ uint8_t MBREnabled(); /** Is the MBRDone flag set */ uint8_t MBRDone(); /** Is the Locked flag set */ uint8_t Locked(); /** Is the Locking SP enabled */ uint8_t LockingEnabled(); /** Is there an OS disk represented by this object */ uint8_t isPresent(); /** Returns the Firmware revision reported by the identify command */ char *getFirmwareRev(); /** Returns the Model Number reported by the Identify command */ char *getModelNum(); /** Returns the Serial Number reported by the Identify command */ char *getSerialNum(); /* What type of disk attachment is used */ DTA_DEVICE_TYPE getDevType(); /** displays the information returned by the Discovery 0 reply */ virtual void puke(); /** Decode the Discovery 0 response. Scans the D0 response and creates a structure * that can be queried later as required.This code also takes care of * the endianess conversions either via a bitswap in the structure or executing * a macro when the input buffer is read. */ void discovery0(); /* * virtual methods required in the OS specific * device class */ /** OS specific initialization. * This function should perform the necessary authority and environment checking * to allow proper functioning of the program, open the device, perform an ATA * identify, add the fields from the identify response to the disk info structure * and if the device is an ATA device perform a call to Discovery0() to complete * the disk_info structure * @param devref character representation of the device is standard OS lexicon */ virtual void init(const char * devref) = 0; /** OS specific method to send an ATA command to the device * @param cmd ATA command to be sent to the device * @param protocol security protocol to be used in the command * @param comID communications ID to be used * @param buffer input/output buffer * @param bufferlen length of the input/output buffer */ virtual uint8_t sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, void * buffer, uint32_t bufferlen) = 0; /** OS specific command to Wait for specified number of milliseconds * @param milliseconds number of milliseconds to wait */ virtual void osmsSleep(uint32_t milliseconds) = 0; /** OS specific routine to send an ATA identify to the device */ virtual void identify(OPAL_DiskInfo& disk_info) = 0; /** OS specific routine to get size of the device */ virtual unsigned long long getSize() = 0; /* * virtual functions required to be implemented * because they are called by sedutil.cpp */ /** User command to prepare the device for management by sedutil. * Specific to the SSC that the device supports * @param password the password that is to be assigned to the SSC master entities */ virtual uint8_t initialSetup(char * password) = 0; /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. * @param lockingrange locking range number to enable * @param start LBA to start locking range * @param length length (in blocks) for locking range * @param Admin1Password admin1 password for TPer * @param password User password to set for locking range */ virtual uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) = 0; /** Set the SID password. * Requires special handling because password is not always hashed. * @param oldpassword current SID password * @param newpassword value password is to be changed to * @param hasholdpwd is the old password to be hashed before being added to the bytestream * @param hashnewpwd is the new password to be hashed before being added to the bytestream */ virtual uint8_t setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) = 0; /** Set the password of a locking SP user. * @param password current password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ virtual uint8_t setPassword(char * password, char * userid, char * newpassword) = 0; /** Set the password of a locking SP user in Single User Mode. * @param password current user password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ virtual uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) = 0; /** Loads a disk image file to the shadow MBR table. * @param password the password for the administrative authority with access to the table * @param filename the filename of the disk image */ virtual uint8_t loadPBA(char * password, char * filename) = 0; /** Change the locking state of a locking range * @param lockingrange The number of the locking range (0 = global) * @param lockingstate the locking state to set * @param Admin1Password password of administrative authority for locking range */ virtual uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * Admin1Password) = 0; /** Change the locking state of a locking range in Single User Mode * @param lockingrange The number of the locking range (0 = global) * @param lockingstate the locking state to set * @param password password of user authority for the locking range */ virtual uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password) = 0; /** Change the active state of a locking range * @param lockingrange The number of the locking range (0 = global) * @param enabled enable (true) or disable (false) the lockingrange * @param password Password of administrative authority for locking range */ virtual uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) = 0; /** Setup a locking range. Initialize a locking range, set it's start * LBA and length, initialize it as unlocked with locking disabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @param password Password of administrator */ virtual uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) = 0; /** Setup a locking range in Single User Mode. Initialize a locking range, * set it's start LBA and length, initialize it as unlocked with locking enabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @param password Password of administrator */ virtual uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) = 0; /** List status of locking ranges. * @param password Password of administrator */ virtual uint8_t listLockingRanges(char * password, int16_t rangeid) = 0; /** Generate a new encryption key for a locking range. * @param lockingrange locking range number * @param password password of the locking administrative authority */ virtual uint8_t rekeyLockingRange(uint8_t lockingrange, char * password) = 0; /** Enable bands using MSID. * @param lockingrange locking range number */ virtual uint8_t setBandsEnabled(int16_t rangeid, char * password) = 0; /** Primitive to set the MBRDone flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ virtual uint8_t setMBRDone(uint8_t state, char * Admin1Password) = 0; /** Primitive to set the MBREnable flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ virtual uint8_t setMBREnable(uint8_t state, char * Admin1Password) = 0; /** enable a locking sp user. * @param password password of locking sp administrative authority * @param userid the user to be enabled */ virtual uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE) = 0; /** Enable locking on the device * @param password password of the admin sp SID authority */ virtual uint8_t activateLockingSP(char * password) = 0; /** Enable locking on the device in Single User Mode * @param lockingrange the locking range number to activate in SUM * @param password password of the admin sp SID authority */ virtual uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password) = 0; /** Erase a Single User Mode locking range by calling the drive's erase method * @param lockingrange The Locking Range to erase * @param password The administrator password for the drive */ virtual uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password) = 0; /** Change the SID password from it's MSID default * @param newpassword new password for SID and locking SP admins */ virtual uint8_t takeOwnership(char * newpassword) = 0; /** Reset the Locking SP to its factory default condition * ERASES ALL DATA! * @param password of Administrative user * @param keep true false for noerase function NOT WWORKING */ virtual uint8_t revertLockingSP(char * password, uint8_t keep = 0) = 0; /** Reset the TPER to its factory condition * ERASES ALL DATA! * @param password password of authority (SID or PSID) * @param PSID true or false is the authority the PSID * */ virtual uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0 ) = 0; /** Erase a locking range * @param lockingrange The number of the locking range (0 = global) * @param password Password of administrative authority for locking range */ virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password) = 0; /** Dumps an object for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param objID the UID of the object to dump * */ virtual uint8_t objDump(char *sp, char * auth, char *pass, char * objID) = 0; /** Issue any command to the drive for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param invoker caller of the method * @param method the method to call * @param plist the parameter list for the command * */ virtual uint8_t rawCmd(char *sp, char * auth, char *pass, char *invoker, char *method, char *plist) = 0; /** Read MSID */ virtual uint8_t printDefaultPassword() = 0; /* * virtual functions required to be implemented * because they are called by DtaSession.cpp */ /** Send a command to the device and wait for the response * @param cmd the MswdCommand object containing the command * @param response the DtaResonse object containing the response * @param protocol The security protocol number to use for the command */ virtual uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01) = 0; /** return the communications ID to be used for sessions to this device */ virtual uint16_t comID() = 0; bool no_hash_passwords; /** disables hashing of passwords */ sedutiloutput output_format; /** standard, readable, JSON */ protected: const char * dev; /**< character string representing the device in the OS lexicon */ uint8_t isOpen = FALSE; /**< The device has been opened */ OPAL_DiskInfo disk_info; /**< Structure containing info from identify and discovery 0 */ DtaResponse response; /**< shared response object */ DtaResponse propertiesResponse; /**< response fron properties exchange */ DtaSession *session; /**< shared session object pointer */ uint8_t discovery0buffer[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; uint32_t tperMaxPacket = 2048; uint32_t tperMaxToken = 1950; }; sedutil-1.20.0/Common/DtaDevEnterprise.cpp000066400000000000000000001527171410717517300204320ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This software is Copyright 2017 Spectra Logic Corporation This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include #include #include #include "DtaDevEnterprise.h" #include "DtaHashPwd.h" #include "DtaEndianFixup.h" #include "DtaStructures.h" #include "DtaCommand.h" #include "DtaResponse.h" #include "DtaSession.h" #include "DtaHexDump.h" #include "DtaAnnotatedDump.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4100) #endif using namespace std; //////////////////////////////////////////////////////////////////////////////// static const bool is_NULL_UID(std::vector & v) //////////////////////////////////////////////////////////////////////////////// { return v.size() == 9 && v[0] == 0xa8 && v[1] == 0x00 && v[2] == 0x00 && v[3] == 0x00 && v[4] == 0x00 && v[5] == 0x00 && v[6] == 0x00 && v[7] == 0x00 && v[8] == 0x00 ; } //////////////////////////////////////////////////////////////////////////////// static void set8(vector & v, const uint8_t value[8]) //////////////////////////////////////////////////////////////////////////////// { v.clear(); v.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { v.push_back(value[i]); } } //////////////////////////////////////////////////////////////////////////////// static void setband(vector & v, uint16_t i) //////////////////////////////////////////////////////////////////////////////// { const uint16_t j = i+1; v[1+6] = (uint8_t(j >> 8) | v[1+6]) & 0xF0; v[1+7] = uint8_t(j); } //////////////////////////////////////////////////////////////////////////////// static void user2cpin(vector & dst, vector & src) //////////////////////////////////////////////////////////////////////////////// { // this works for BandMasterN and EraseMaster // Table 29 Locking C_PIN table, p. 72 of Enterprise SSC rev 3.00 dst = src; dst[1+3] = 0x0B; } //////////////////////////////////////////////////////////////////////////////// uint8_t DtaDevEnterprise::getMaxRanges(char * password, uint16_t *maxRanges) //////////////////////////////////////////////////////////////////////////////// { uint8_t lastRC; // 5.7.2.1.5 MaxRanges // This value defines the maximum number of supportable LBA ranges in addition // to the Global Range. If this value is 0, then the only range available is // the entire Global Range of the Storage Device. // // Therefore: 0 <= supported range <= MaxRanges // create session session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID)) != 0) { delete session; return lastRC; } //** Table 36 "LockingInfo table", p. 72 of Enterprise SSC rev 3.00 vector table; set8(table, OPALUID[ENTERPRISE_LOCKING_INFO_TABLE]); // query row 1 of LockingInfo table if ((lastRC = getTable(table, "MaxRanges", "MaxRanges")) != 0) { delete session; return getMaxRangesOpal(password, maxRanges); } delete session; // "MaxRanges" is token 5 of response *maxRanges = response.getUint16(5); return 0; } //////////////////////////////////////////////////////////////////////////////// uint8_t DtaDevEnterprise::getMaxRangesOpal(char * password, uint16_t *maxRanges) //////////////////////////////////////////////////////////////////////////////// { uint8_t lastRC; // create session session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID)) != 0) { delete session; return lastRC; } //** Table 36 "LockingInfo table", p. 72 of Enterprise SSC rev 3.00 vector table; set8(table, OPALUID[OPAL_LOCKING_INFO_TABLE]); // query row 1 of LockingInfo table if ((lastRC = getTable(table, "MaxRanges", "MaxRanges")) != 0) { LOG(E) << "Unable to get MaxRanges from LockingInfo table"; delete session; return lastRC; } delete session; // "MaxRanges" is token 5 of response *maxRanges = response.getUint16(5); return 0; } DtaDevEnterprise::DtaDevEnterprise(const char * devref) { DtaDevOS::init(devref); assert(isEprise()); if (properties()) { LOG(E) << "Properties exchange failed"; } } DtaDevEnterprise::~DtaDevEnterprise() { } uint8_t DtaDevEnterprise::initialSetup(char * password) { LOG(D1) << "Entering initialSetup()"; uint8_t lastRC; if ((lastRC = takeOwnership(password)) != 0) { LOG(E) << "Initial setup failed - unable to take ownership"; return lastRC; } if ((lastRC = setLockingRange(0, OPAL_LOCKINGSTATE::READWRITE, password)) != 0) { LOG(E) << "Initial setup failed - unable to unlock for read/write"; return lastRC; } if ((lastRC = configureLockingRange(0, (DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), password)) != 0) { LOG(E) << "Initial setup failed - unable to enable read/write locking"; return lastRC; } LOG(I) << "Initial setup of TPer complete on " << dev; LOG(D1) << "Exiting initialSetup()"; return 0; } uint8_t DtaDevEnterprise::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) { LOG(D1) << "Entering DtaDevEnterprise::setup_SUM"; LOG(I) << "setup_SUM not supported on DtaDevEnterprise"; return 1; } uint8_t DtaDevEnterprise::configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevEnterprise::configureLockingRange()"; //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 std::vector user; set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); setband(user, lockingrange); //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector object; set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); setband(object, lockingrange); session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { delete session; return lastRC; } /* can't use settable because the segate drives require that both the * read & write lockenabled be changed at the same time. I can find no * written doc on such a restriction but ..... */ vector method; set8(method, OPALMETHOD[OPAL_METHOD::ESET]); DtaCommand *set = new DtaCommand(); if (set == NULL) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(object, method); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("ReadLockEnabled"); set->addToken((enabled & DTA_READLOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("WriteLockEnabled"); set->addToken((enabled & DTA_WRITELOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("LockOnReset"); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(UINT_00); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "Set Failed "; delete session; delete set; return lastRC; } delete set; delete session; LOG(I) << "Locking range configured " << (uint16_t) enabled; LOG(D1) << "Exiting DtaDevEnterprise::configureLockingRange()"; return 0; } uint8_t DtaDevEnterprise::rekeyLockingRange(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevEnterprise::rekeyLockingRange()"; uint8_t lastRC; //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector user; set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); setband(user, lockingrange); //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector table; set8(table, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); setband(table, lockingrange); session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { delete session; return lastRC; } if ((lastRC = getTable(table, "ActiveKey", "ActiveKey")) != 0) { delete session; return lastRC; } std::vector ActiveKey = response.getRawToken(5); if (is_NULL_UID(ActiveKey)) { LOG(I) << "LockingRange" << (uint16_t)lockingrange << " remains in plaintext "; delete session; return 0; } DtaCommand *rekey = new DtaCommand(); if (NULL == rekey) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); rekey->changeInvokingUid(ActiveKey); rekey->addToken(OPAL_TOKEN::STARTLIST); rekey->addToken(OPAL_TOKEN::ENDLIST); rekey->complete(); if ((lastRC = session->sendCommand(rekey, response)) != 0) { LOG(E) << "rekeyLockingRange Failed "; delete rekey; delete session; return lastRC; } delete rekey; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " reKeyed "; LOG(D1) << "Exiting DtaDevEnterprise::rekeyLockingRange()"; return 0; } uint8_t DtaDevEnterprise::revertLockingSP(char * password, uint8_t keep) { LOG(D1) << "Entering DtaDevEnterprise::revertLockingSP()"; if(password == NULL) { LOG(D4) << "Referencing formal parameters " << keep; } uint8_t lastRC; DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } OPAL_UID uid = OPAL_UID::OPAL_SID_UID; if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { delete cmd; delete session; return lastRC; } cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken("KeepGlobalRangeKey"); cmd->addToken(keep); cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); session->expectAbort(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "revertLockingSP completed successfully"; delete cmd; delete session; LOG(D1) << "Exiting DtaDevEnterprise::revertLockingSP()"; return 0; } uint8_t DtaDevEnterprise::setPassword(char * password, char * userid, char * newpassword) { LOG(D1) << "Entering DtaDevEnterprise::setPassword" ; uint8_t lastRC; string defaultPassword; char *pwd = password, *newpwd = newpassword; if (11 > strnlen(userid, 15)) { LOG(E) << "Invalid Userid " << userid; return DTAERROR_INVALID_PARAMETER; } std::vector user; if (!memcmp("BandMaster", userid, 10)) { uint16_t band = (uint16_t)atoi(&userid[10]); if (1023 < band) { LOG(E) << "Invalid Userid " << userid; return DTAERROR_INVALID_PARAMETER; } set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); setband(user, band); } else if (!memcmp("EraseMaster", userid, 11)) { set8(user, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); } else { LOG(E) << "Invalid Userid " << userid; return DTAERROR_INVALID_PARAMETER; } if ((password == NULL) || (*password == '\0') || (newpassword == NULL) || (*newpassword == '\0')) { if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << "setPassword failed to retrieve MSID"; return lastRC; } defaultPassword = response.getString(5); if ((password == NULL) || (*password == '\0')) pwd = (char *)defaultPassword.c_str(); if ((newpassword == NULL) || (*newpassword == '\0')) newpwd = (char *)defaultPassword.c_str(); } std::vector usercpin; user2cpin(usercpin, user); session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((password == NULL) || (*password == '\0')) session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) { delete session; return lastRC; } if ((newpassword == NULL) || (*newpassword == '\0')) { std::vector tmppwd; tmppwd.push_back(0xd0); tmppwd.push_back((uint8_t)strnlen(newpwd, 255)); for (unsigned int i = 0; i < strnlen(newpwd, 255); i++) { tmppwd.push_back(newpwd[i]); } if ((lastRC = setTable(usercpin, "PIN", tmppwd)) != 0) { LOG(E) << "Unable to set user " << userid << " new password "; delete session; return lastRC; } } else { std::vector hash; DtaHashPwd(hash, newpwd, this); if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { LOG(E) << "Unable to set user " << userid << " new password "; delete session; return lastRC; } } LOG(I) << userid << " password changed"; delete session; LOG(D1) << "Exiting DtaDevEnterprise::setPassword()"; return 0; } uint8_t DtaDevEnterprise::setNewPassword_SUM(char * password, char * userid, char * newpassword) { LOG(D1) << "Entering DtaDevEnterprise::setNewPassword_SUM()"; LOG(I) << "setNewPassword_SUM is not in the Enterprise SSC and not supported"; LOG(D1) << "Exiting DtaDevEnterprise::setNewPassword_SUM()"; return 0; } uint8_t DtaDevEnterprise::setMBREnable(uint8_t mbrstate, char * Admin1Password) { LOG(D1) << "Entering DtaDevEnterprise::setMBREnable"; if (NULL == Admin1Password) { LOG(E) << "This shouldn't happen " << mbrstate; } LOG(I) << "MBR shadowing is optional in the Enterprise SSC and not supported"; LOG(D1) << "Exiting DtaDevEnterprise::setMBREnable"; return 0; } uint8_t DtaDevEnterprise::setMBRDone(uint8_t mbrstate, char * Admin1Password) { LOG(D1) << "Entering DtaDevEnterprise::setMBRDone"; if (NULL == Admin1Password) { LOG(E) << "This shouldn't happen " << mbrstate; } LOG(I) << "MBR shadowing is optional in the Enterprise SSC and not supported"; LOG(D1) << "Exiting DtaDevEnterprise::setMBRDone"; return 0; } uint8_t DtaDevEnterprise::setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevEnterprise::setupLockingRange"; // look up MaxRanges uint16_t MaxRanges; if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { return (lastRC); } if (MaxRanges == 0 || MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; // make sure lockingrange is in bounds if (lockingrange > MaxRanges) { LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector user; set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); setband(user, lockingrange); //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector object; set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); setband(object, lockingrange); vector method; set8(method, OPALMETHOD[OPAL_METHOD::ESET]); DtaCommand *set = new DtaCommand(); set->reset(object, method); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("RangeStart"); set->addToken(start); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("RangeLength"); set->addToken(length); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("ReadLockEnabled"); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("WriteLockEnabled"); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("ReadLocked"); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("WriteLocked"); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("LockOnReset"); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { delete session; return lastRC; } if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "setupLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << " for " << length << " blocks configured as unlocked range"; LOG(D1) << "Exiting DtaDevEnterprise::setupLockingRange"; return 0; } uint8_t DtaDevEnterprise::setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) { LOG(D1) << "Entering DtaDevEnterprise::setupLockingRange_SUM"; if (0 == lockingrange) { LOG(E) << start << length << password; } LOG(D1) << "Exiting DtaDevEnterprise::setupLockingRange_SUM"; return 0; } //////////////////////////////////////////////////////////////////////////////// uint8_t DtaDevEnterprise::listLockingRanges(char * password, int16_t rangeid) //////////////////////////////////////////////////////////////////////////////// { LOG(D1) << "Entering DtaDevEnterprise::listLockingRanges"; uint8_t lastRC = 0, failRC = 0; int one_succeeded = 0; string defaultPassword; char *pwd = NULL; // if (NULL == password) { LOG(E) << "password NULL"; } if ((password == NULL) || (*password == '\0')) { if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << __func__ << ": unable to retrieve MSID"; return lastRC; } defaultPassword = response.getString(5); pwd = (char *)defaultPassword.c_str(); } else { pwd = password; } // look up MaxRanges uint16_t MaxRanges; if (rangeid == -1) { lastRC = getMaxRanges(password, &MaxRanges); if (lastRC != 0) return lastRC; } else MaxRanges = rangeid; if (MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; if(rangeid == -1) { LOG(I) << "Maximum ranges supported: " << MaxRanges; } //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector user; user.clear(); set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector table; table.clear(); set8(table, OPALUID[OPAL_LOCKINGRANGE_GLOBAL]); uint16_t start = (rangeid == -1)? 0: rangeid; for (uint16_t i = start; i <= MaxRanges; i++) { uint8_t curRC = 0; setband(user, i); setband(table, i); if (output_format == sedutilNormal) { LOG(I) << "Band[" << i << "]:"; } session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if (!defaultPassword.empty()) session->dontHashPwd(); if ((curRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) { if ((output_format == sedutilNormal) || (rangeid != -1)) { LOG(I) << " could not establish session for row[" << i << "]"; } failRC = curRC; delete session; continue; } if (getTable(table, "Name", "LockOnReset")) { LOG(I) << " row[" << i << "] not found in LOCKING table"; delete session; continue; } // 00 1 ( F0 ) Start_List // 01 1 ( F0 ) Start_List // 02 1 ( F0 ) Start_List // 03 1 ( F2 ) Start_Name // 04 5 ( A4 ) 4E 61 6D 65 ("Name") // 05* 6 ( A5 ) 42 61 6E 64 31 ("Band1") // 06 1 ( F3 ) End_Name // 07 1 ( F2 ) Start_Name // 08 11 ( AA ) 43 6F 6D 6D 6F 6E 4E 61 6D 65 ("CommonName") // 09* 8 ( A7 ) 4C 6F 63 6B 69 6E 67 ("Locking") // 10 1 ( F3 ) End_Name // 11 1 ( F2 ) Start_Name // 12 11 ( AA ) 52 61 6E 67 65 53 74 61 72 74 ("RangeStart") // 13* 1 ( 00 ) 0 (0h) // 14 1 ( F3 ) End_Name // 15 1 ( F2 ) Start_Name // 16 12 ( AB ) 52 61 6E 67 65 4C 65 6E 67 74 68 ("RangeLength") // 17* 1 ( 00 ) 0 (0h) // 18 1 ( F3 ) End_Name // 19 1 ( F2 ) Start_Name // 20 16 ( AF ) 52 65 61 64 4C 6F 63 6B 45 6E 61 62 6C 65 64 ("ReadLockEnabled") // 21* 1 ( 00 ) 0 (0h) // 22 1 ( F3 ) End_Name // 23 1 ( F2 ) Start_Name // 24 18 ( D0 10 ) 57 72 69 74 65 4C 6F 63 6B 45 6E 61 62 6C 65 64 ("WriteLockEnabled") // 25* 1 ( 00 ) 0 (0h) // 26 1 ( F3 ) End_Name // 27 1 ( F2 ) Start_Name // 28 11 ( AA ) 52 65 61 64 4C 6F 63 6B 65 64 ("ReadLocked") // 29* 1 ( 01 ) 1 (1h) // 30 1 ( F3 ) End_Name // 31 1 ( F2 ) Start_Name // 32 12 ( AB ) 57 72 69 74 65 4C 6F 63 6B 65 64 ("WriteLocked") // 33* 1 ( 01 ) 1 (1h) // 34 1 ( F3 ) End_Name // 35 1 ( F2 ) Start_Name // 36 12 ( AB ) 4C 6F 63 6B 4F 6E 52 65 73 65 74 ("LockOnReset") // 37 1 ( F0 ) Start_List // 38 1 ( 00 ) 0 (0h) // 39 1 ( F1 ) End_List // 40 1 ( F3 ) End_Name const std::string Name = response.getString(5+4*0); const std::string CommonName = response.getString(5+4*1); const uint64_t RangeStart = response.getUint64(5+4*2); const uint64_t RangeLength = response.getUint64(5+4*3); const bool ReadLockEnabled = response.getUint8(5+4*4) != 0; const bool WriteLockEnabled = response.getUint8(5+4*5) != 0; const bool ReadLocked = response.getUint8(5+4*6) != 0; const bool WriteLocked = response.getUint8(5+4*7) != 0; // LockOnReset list has at least one element const bool LockOnReset = response.tokenIs(5+4*8) == STARTLIST && response.tokenIs(5+4*8+1) == DTA_TOKENID_UINT; delete session; if (output_format == sedutilReadable) { LOG(I) << "Band[" << i << "]: "; } LOG(I) << " Name: " << Name; LOG(I) << " CommonName: " << CommonName; LOG(I) << " RangeStart: " << RangeStart; LOG(I) << " RangeLength: " << RangeLength; LOG(I) << " ReadLockEnabled: " << ReadLockEnabled; LOG(I) << " WriteLockEnabled:" << WriteLockEnabled; LOG(I) << " ReadLocked: " << ReadLocked; LOG(I) << " WriteLocked: " << WriteLocked; LOG(I) << " LockOnReset: " << LockOnReset; one_succeeded = 1; } // If we're getting the list of ranges and none succeed, that is an error. // If we're getting one range, return any failure. if (((rangeid == -1) && (one_succeeded == 0)) || (rangeid != -1)) lastRC = failRC; LOG(D1) << "Exiting DtaDevEnterprise::listLockingRanges"; return lastRC; } uint8_t DtaDevEnterprise::setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * password) { LOG(D1) << "Entering DtaDevEnterprise::setLockingRange"; uint8_t lastRC; // convert Opal lockingstate to boolean OPAL_TOKEN locked; switch (lockingstate) { case OPAL_LOCKINGSTATE::READWRITE: locked = OPAL_TOKEN::OPAL_FALSE; break; case OPAL_LOCKINGSTATE::READONLY: LOG(E) << "Read Only locking state is unsupported in Enterprise SSC"; return DTAERROR_INVALID_PARAMETER; case OPAL_LOCKINGSTATE::LOCKED: locked = OPAL_TOKEN::OPAL_TRUE; break; default: LOG(E) << "Invalid locking state for setLockingRange (RW=1, LOCKED=3)"; return DTAERROR_INVALID_PARAMETER; } // look up MaxRanges uint16_t MaxRanges; if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { return lastRC; } if (MaxRanges == 0 || MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; // make sure lockingrange is in bounds if (lockingrange > MaxRanges) { LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector user; set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); setband(user, lockingrange); //** Band0 UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector object; set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); setband(object, lockingrange); vector method; set8(method, OPALMETHOD[OPAL_METHOD::ESET]); DtaCommand *set = new DtaCommand(); set->reset(object, method); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("WriteLocked"); set->addToken(locked); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken("ReadLocked"); set->addToken(locked); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { delete session; return lastRC; } if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "Set Failed "; delete session; delete set; return lastRC; } delete set; delete session; LOG(I) << "Locking range Read/Write set " << (uint16_t)locked; LOG(D1) << "Exiting DtaDevEnterprise::setLockingRange"; return 0; } uint8_t DtaDevEnterprise::setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password) { LOG(D1) << "Entering DtaDevEnterprise::setLockingRange_SUM()"; LOG(E) << "setLockingRange_SUM not implemented"; LOG(D1) << "Exiting DtaDevEnterprise::setLockingRange_SUM()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::enableUser(char * password, char * userid, OPAL_TOKEN status) { LOG(D1) << "Entering DtaDevEnterprise::enableUser"; LOG(E) << "enableUser not implemented"; if (!password && !userid) { LOG(E) << "Formal Parameters"; } LOG(D1) << "Exiting DtaDevEnterprise::enableUser()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::revertTPer(char * password, uint8_t PSID, uint8_t AdminSP) { LOG(D1) << "Entering DtaDevEnterprise::revertTPer()"; if (password == NULL) { LOG(D4) << "Referencing formal parameters " << PSID; } uint8_t lastRC; DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } OPAL_UID uid = OPAL_UID::OPAL_SID_UID; if (PSID) { session->dontHashPwd(); // PSID pwd should be passed as entered uid = OPAL_UID::OPAL_PSID_UID; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { delete cmd; delete session; return lastRC; } if (AdminSP) cmd->reset(OPAL_UID::OPAL_ADMINSP_UID, OPAL_METHOD::REVERT); else cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); session->expectAbort(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "revertTper completed successfully"; delete cmd; delete session; LOG(D1) << "Exiting DtaDevEnterprise::revertTPer()"; return 0; } uint8_t DtaDevEnterprise::eraseLockingRange(uint8_t lockingrange, char * password) { uint8_t lastRC; string defaultPassword; char *pwd = NULL; LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange"; // look up MaxRanges uint16_t MaxRanges = 0; if ((password == NULL) || (*password == '\0')) { if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << __func__ << ": unable to retrieve MSID"; return lastRC; } defaultPassword = response.getString(5); pwd = (char *)defaultPassword.c_str(); } else { pwd = password; } if ((lastRC = getMaxRanges(pwd, &MaxRanges)) != 0) { return lastRC; } if (MaxRanges == 0 || MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; // make sure lockingrange is in bounds if (lockingrange > MaxRanges) { LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } //** EraseMaster UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector user; set8(user, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); //** Band0 UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 vector object; set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); setband(object, lockingrange); vector method; set8(method, OPALMETHOD[OPAL_METHOD::ERASE]); DtaCommand *erase = new DtaCommand(); if (erase == NULL) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } erase->reset(object, method); erase->addToken(OPAL_TOKEN::STARTLIST); erase->addToken(OPAL_TOKEN::ENDLIST); erase->complete(); session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if (!defaultPassword.empty()) session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) { delete session; return lastRC; } if ((lastRC = session->sendCommand(erase, response)) != 0) { LOG(E) << "eraseLockingRange Failed "; delete erase; delete session; return lastRC; } delete erase; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " erased"; LOG(D1) << "Exiting DtaDevEnterprise::eraseLockingRange"; return 0; } uint8_t DtaDevEnterprise::loadPBA(char * password, char * filename) { LOG(D1) << "Entering DtaDevEnterprise::loadPBAimage()" << filename << " " << dev; if (password == NULL) { LOG(D4) << "Referencing formal parameters " << filename; } LOG(I) << "loadPBA is not implemented. It is not a mandatory part of "; LOG(I) << "the enterprise SSC "; LOG(D1) << "Exiting DtaDevEnterprise::loadPBAimage()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::activateLockingSP(char * password) { LOG(D1) << "Entering DtaDevEnterprise::activateLockingSP()"; if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } LOG(E) << "activate Locking SP is not a part of the Enterprise SSC "; LOG(D1) << "Exiting DtaDevEnterprise::activatLockingSP()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::activateLockingSP_SUM(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevEnterprise::activateLockingSP_SUM()"; if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } LOG(E) << "activate Locking SP SUM is not a part of the Enterprise SSC "; LOG(D1) << "Exiting DtaDevEnterprise::activateLockingSP_SUM()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::eraseLockingRange_SUM(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange_SUM()"; if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } LOG(E) << "Erase Locking Range SUM is not a part of the Enterprise SSC "; LOG(D1) << "Exiting DtaDevEnterprise::eraseLockingRange_SUM()"; return DTAERROR_INVALID_PARAMETER; } uint8_t DtaDevEnterprise::takeOwnership(char * newpassword) { string defaultPassword; uint8_t lastRC; LOG(D1) << "Entering DtaDevEnterprise::takeOwnership()"; if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << "takeOwnership failed unable to retrieve MSID"; return lastRC; } defaultPassword = response.getString(5); if ((lastRC = setSIDPassword((char *)defaultPassword.c_str(), newpassword, 0)) != 0) { LOG(E) << "takeOwnership failed unable to set new SID password"; return lastRC; } if ((lastRC = initLSPUsers((char *)defaultPassword.c_str(), newpassword)) != 0) { LOG(E) << "takeOwnership failed unable to set Locking SP user passwords"; return lastRC; } LOG(I) << "takeOwnership complete"; LOG(D1) << "Exiting takeOwnership()"; return 0; } //////////////////////////////////////////////////////////////////////////////// uint8_t DtaDevEnterprise::setBandsEnabled(int16_t lockingrange, char * password) //////////////////////////////////////////////////////////////////////////////// { uint8_t lastRC = 0; LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange"; // look up MaxRanges uint16_t MaxRanges = 0; if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { return lastRC; } if (MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; // calculate starting and ending bands int lo, hi; if (lockingrange < 0) { lo = 0; hi = MaxRanges; } else if (lockingrange > MaxRanges) { LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } else { lo = lockingrange; hi = lockingrange; } // get password (usually MSID) string pwd; const bool useMSID = password == NULL || *password == '\0'; if (!useMSID) { pwd = password; } else { if ((lastRC = getDefaultPassword()) != 0) return lastRC; pwd = response.getString(5); } vector erasemaster; set8(erasemaster, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 vector object; set8(object, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); // method is enterprise set vector method; set8(method, OPALMETHOD[OPAL_METHOD::ESET]); // set Enabled=TRUE in BandMaster[n] row of (Table 28) Locking SP Authority for(int n=lo; n<=hi && lastRC==0; n++) { // BandMaster[n] row setband(object, (uint16_t) n); // command to set Enabled column DtaCommand *cmd = new DtaCommand(); if (cmd == NULL) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } cmd->reset(object, method); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken("Enabled"); cmd->addToken(OPAL_TRUE); cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); // create session to use with erasemaster session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } // MSID ? if (useMSID) session->dontHashPwd(); // start session lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, (char *)pwd.c_str(), erasemaster); if (lastRC == 0) { // send command lastRC = session->sendCommand(cmd, response); } delete cmd; delete session; } return lastRC; } uint8_t DtaDevEnterprise::initLSPUsers(char * defaultPassword, char * newPassword) { vector user, usercpin, hash, erasemaster, table; uint8_t lastRC; LOG(D1) << "Entering DtaDevEnterprise::initLSPUsers()"; // do erasemaster session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } session->dontHashPwd(); set8(erasemaster, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, defaultPassword, erasemaster)) != 0) { delete session; return lastRC; } DtaHashPwd(hash, newPassword, this); user2cpin(usercpin, erasemaster); if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { LOG(E) << "Unable to set new EraseMaster password "; delete session; return lastRC; } LOG(I) << "EraseMaster password set"; delete session; // look up MaxRanges uint16_t MaxRanges = 0; if ((lastRC = getMaxRanges(NULL, &MaxRanges)) != 0) { return lastRC; } if (MaxRanges == 0 || MaxRanges >= 1024) return DTAERROR_UNSUPORTED_LOCKING_RANGE; LOG(I) << "Maximum ranges supported " << MaxRanges; // do bandmasters set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); for (uint16_t i = 0; i <= MaxRanges; i++) { setband(user, i); LOG(D3) << "initializing BandMaster" << (uint16_t) i; session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, defaultPassword, user)) != 0) { delete session; // We only return failure if we fail to set BandMaster0. if (i == 0) { return lastRC; } else { continue; } } DtaHashPwd(hash, newPassword, this); user2cpin(usercpin, user); if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { LOG(E) << "Unable to set BandMaster" << (uint16_t) i << " new password "; // We only return failure if we fail to set BandMaster0. if (i == 0) { delete session; return lastRC; } } else { LOG(I) << "BandMaster" << (uint16_t) i << " password set"; } delete session; } LOG(D1) << "Exiting DtaDevEnterprise::initLSPUsers()"; return 0; } uint8_t DtaDevEnterprise::getDefaultPassword() { LOG(D1) << "Entering DtaDevEnterprise::getDefaultPassword()"; uint8_t lastRC; vector hash; session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID)) != 0) { LOG(E) << "Unable to start Unauthenticated session " << dev; delete session; return lastRC; } vector table; table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_MSID][i]); } if ((lastRC = getTable(table, "PIN", "PIN")) != 0) { delete session; return lastRC; } delete session; LOG(D1) << "Exiting getDefaultPassword()"; return 0; } uint8_t DtaDevEnterprise::printDefaultPassword() { const uint8_t rc = getDefaultPassword(); if (rc) { LOG(E) << "unable to retrieve MSID"; return rc; } string defaultPassword = response.getString(5); fprintf(stdout, "MSID: %s\n", (char *)defaultPassword.c_str()); return 0; } uint8_t DtaDevEnterprise::setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd, uint8_t hashnewpwd) { LOG(D1) << "Entering DtaDevEnterprise::setSIDPassword()"; uint8_t lastRC; vector user; set8(user, OPALUID[OPAL_SID_UID]); vector usercpin; set8(usercpin, OPALUID[OPAL_C_PIN_SID]); if (*oldpassword == '\0') { if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << "setPassword failed to retrieve MSID"; return lastRC; } string defaultPassword = response.getString(5); session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, (char *)defaultPassword.c_str(), user)) != 0) { delete session; return lastRC; } } else { session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } session->dontHashPwd(); if (!hasholdpwd) session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, oldpassword, user)) != 0) { delete session; return lastRC; } } vector hash; if (hashnewpwd) { DtaHashPwd(hash, newpassword, this); } else { hash.push_back(0xd0); hash.push_back((uint8_t)strnlen(newpassword, 255)); for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) { hash.push_back(newpassword[i]); } } if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { LOG(E) << "Unable to set new SID password "; delete session; return lastRC; } delete session; LOG(D1) << "Exiting DtaDevEnterprise::setSIDPassword()"; return 0; } uint8_t DtaDevEnterprise::setTable(vector table, const char *name, OPAL_TOKEN value) { vector token; token.push_back((uint8_t) value); return(setTable(table, name, token)); } uint8_t DtaDevEnterprise::setTable(vector table, const char *name, vector value) { LOG(D1) << "Entering DtaDevEnterprise::setTable"; uint8_t lastRC; DtaCommand *set = new DtaCommand(); if (set == NULL) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::ESET); set->changeInvokingUid(table); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(name); set->addToken(value); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "Set Failed "; delete set; return lastRC; } delete set; LOG(D1) << "Leaving DtaDevEnterprise::setTable"; return 0; } uint8_t DtaDevEnterprise::getTable(vector table, const char * startcol, const char * endcol) { LOG(D1) << "Entering DtaDevEnterprise::getTable"; uint8_t lastRC; DtaCommand *get = new DtaCommand(); if (get == NULL) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::EGET); get->changeInvokingUid(table); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTNAME); get->addToken("startColumn"); get->addToken(startcol); get->addToken(OPAL_TOKEN::ENDNAME); get->addToken(OPAL_TOKEN::STARTNAME); get->addToken("endColumn"); get->addToken(endcol); get->addToken(OPAL_TOKEN::ENDNAME); get->addToken(OPAL_TOKEN::ENDLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->complete(); if ((lastRC = session->sendCommand(get, response)) != 0) { delete get; return lastRC; } delete get; return 0; } uint16_t DtaDevEnterprise::comID() { LOG(D1) << "Entering DtaDevEnterprise::comID()"; return disk_info.Enterprise_basecomID; } uint8_t DtaDevEnterprise::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) { uint8_t rc = 0; OPALHeader * hdr = (OPALHeader *) cmd->getCmdBuffer(); LOG(D3) << endl << "Dumping command buffer"; IFLOG(D) DtaAnnotatedDump(IF_SEND, cmd->getCmdBuffer(), cmd->outputBufferSize()); IFLOG(D3) DtaHexDump(cmd->getCmdBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); rc = sendCmd(IF_SEND, protocol, comID(), cmd->getCmdBuffer(), cmd->outputBufferSize()); if (0 != rc) { LOG(E) << "Command failed on send " << (uint16_t) rc; return rc; } hdr = (OPALHeader *) cmd->getRespBuffer(); do { //LOG(I) << "read loop"; osmsSleep(25); memset(cmd->getRespBuffer(), 0, MIN_BUFFER_LENGTH); rc = sendCmd(IF_RECV, protocol, comID(), cmd->getRespBuffer(), MIN_BUFFER_LENGTH); } while ((0 != hdr->cp.outstandingData) && (0 == hdr->cp.minTransfer)); LOG(D3) << std::endl << "Dumping reply buffer"; IFLOG(D) DtaAnnotatedDump(IF_RECV, cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); if (0 != rc) { LOG(E) << "Command failed on recv" << (uint16_t) rc; return rc; } resp.init(cmd->getRespBuffer()); return 0; } uint8_t DtaDevEnterprise::properties() { LOG(D1) << "Entering DtaDevEnterprise::properties()"; uint8_t lastRC; session = new DtaSession(this); // use the session IO without starting a session if (session == NULL) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } DtaCommand *props = new DtaCommand(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::PROPERTIES); if (props == NULL) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } props->addToken(OPAL_TOKEN::STARTLIST); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("HostProperties"); props->addToken(OPAL_TOKEN::STARTLIST); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxComPacketSize"); props->addToken(2048); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxPacketSize"); props->addToken(2028); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxIndTokenSize"); props->addToken(1992); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxPackets"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxSubpackets"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxMethods"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->complete(); if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { delete props; return lastRC; } disk_info.Properties = 1; delete props; LOG(D1) << "Leaving DtaDevEnterprise::properties()"; return 0; } void DtaDevEnterprise::puke() { LOG(D1) << "Entering DtaDevEnterprise::puke()"; DtaDev::puke(); if (disk_info.Properties) { uint32_t i = 0, j = 0; cout << std::endl << "TPer Properties: " << std::endl; for (i = 0, j = 1; i < propertiesResponse.getTokenCount(); i++) { if (OPAL_TOKEN::ENDLIST == propertiesResponse.tokenIs(i)) { if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i + 1)) { cout << std::endl << "Host Properties: " << std::endl; i += 2; j = 1; continue; } else { break; } } if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING == propertiesResponse.tokenIs(i + 1)) { cout << " " << propertiesResponse.getString(i + 1) << " = " << propertiesResponse.getUint64(i + 2); i += 2; j++; if (!(j % 3)) cout << std::endl; } } } if ((j % 3) != 0) cout << std::endl; } } uint8_t DtaDevEnterprise::rawCmd(char *sp, char *hexauth, char *pass, char *hexinvokingUID, char *hexmethod,char *hexparms) { LOG(D1) << "Entering DtaDevEnterprise::rawCmd"; LOG(D1) << sp << " " << hexauth << " " << pass << " " ; LOG(D1) << hexinvokingUID << " " << hexmethod << " " << hexparms; uint8_t lastRC; vector authority, object, invokingUID, method, parms; uint8_t work; if (16 != strnlen(hexauth, 32)) { LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; return DTAERROR_INVALID_PARAMETER; } authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexauth[i] & 0x40 ? 16 * ((hexauth[i] & 0xf) + 9) : 16 * (hexauth[i] & 0x0f); work += hexauth[i + 1] & 0x40 ? (hexauth[i + 1] & 0xf) + 9 : hexauth[i + 1] & 0x0f; authority.push_back(work); } if (16 != strnlen(hexinvokingUID, 32)) { LOG(E) << "invoker must be 16 byte ascii string of invoking uid"; return DTAERROR_INVALID_PARAMETER; } invokingUID.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexinvokingUID[i] & 0x40 ? 16 * ((hexinvokingUID[i] & 0xf) + 9) : 16 * (hexinvokingUID[i] & 0x0f); work += hexinvokingUID[i + 1] & 0x40 ? (hexinvokingUID[i + 1] & 0xf) + 9 : hexinvokingUID[i + 1] & 0x0f; invokingUID.push_back(work); } if (16 != strnlen(hexmethod, 32)) { LOG(E) << "invoker must be 16 byte ascii string of method uid"; return DTAERROR_INVALID_PARAMETER; } method.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexmethod[i] & 0x40 ? 16 * ((hexmethod[i] & 0xf) + 9) : 16 * (hexmethod[i] & 0x0f); work += hexmethod[i + 1] & 0x40 ? (hexmethod[i + 1] & 0xf) + 9 : hexmethod[i + 1] & 0x0f; method.push_back(work); } if (1020 < strnlen(hexparms, 1024)) { LOG(E) << "Parmlist limited to 1020 characters"; return DTAERROR_INVALID_PARAMETER; } if (strnlen(hexparms, 1024) % 2) { LOG(E) << "Parmlist must be even number of bytes"; return DTAERROR_INVALID_PARAMETER; } for (uint32_t i = 0; i < strnlen(hexparms, 1024); i += 2) { work = hexparms[i] & 0x40 ? 16 * ((hexparms[i] & 0xf) + 9) : 16 * (hexparms[i] & 0x0f); work += hexparms[i + 1] & 0x40 ? (hexparms[i + 1] & 0xf) + 9 : hexparms[i + 1] & 0x0f; parms.push_back(work); } DtaCommand *cmd = new DtaCommand(); if (cmd == NULL) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, method); cmd->changeInvokingUid(invokingUID); cmd->addToken(parms); cmd->complete(); session = new DtaSession(this); if (session == NULL) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start((OPAL_UID) atoi(sp), pass, authority)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "Command:"; cmd->dumpCommand(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "Response:"; cmd->dumpResponse(); delete cmd; delete session; LOG(D1) << "Exiting DtaDevEnterprise::rawCmd"; return 0; } uint8_t DtaDevEnterprise::objDump(char *sp, char * auth, char *pass, char * objID) { LOG(D1) << "Entering DtaDevEnterprise::objDump"; LOG(D1) << sp << " " << auth << " " << pass << " " << objID; DtaCommand *get = new DtaCommand(); vector authority, object; uint8_t work; if (16 != strnlen(auth, 32)) { LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; return 0xff; } if (16 != strnlen(objID, 32)) { LOG(E) << "ObjectID must be 16 byte ascii string of hex object uid"; return 0xff; } authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = auth[i] & 0x40 ? 16 * ((auth[i] & 0xf) + 9) : 16 * (auth[i] & 0x0f); work += auth[i + 1] & 0x40 ? (auth[i + 1] & 0xf) + 9 : auth[i + 1] & 0x0f; authority.push_back(work); } object.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = objID[i] & 0x40 ? 16 * ((objID[i] & 0xf) + 9) : 16 * (objID[i] & 0x0f); work += objID[i + 1] & 0x40 ? (objID[i + 1] & 0xf) + 9 : objID[i + 1] & 0x0f; object.push_back(work); } get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::EGET); get->changeInvokingUid(object); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->complete(); LOG(I) << "Command:"; get->dumpCommand(); session = new DtaSession(this); if (session->start((OPAL_UID)atoi(sp), pass, authority)) { delete get; delete session; return 0xff; } if (session->sendCommand(get, response)) { delete get; delete session; return 0xff; } LOG(I) << "Response:"; get->dumpResponse(); delete get; delete session; LOG(D1) << "Exiting DtaDevEnterprise::objDump"; return 0; } #ifdef _MSC_VER #pragma warning(pop) #endif sedutil-1.20.0/Common/DtaDevEnterprise.h000066400000000000000000000235121410717517300200650ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This software is Copyright 2017 Spectra Logic Corporation This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once class DtaCommand; class DtaSession; #include "os.h" #include "DtaOptions.h" #include "DtaDev.h" #include "DtaDevOS.h" #include "DtaStructures.h" #include "DtaLexicon.h" #include "DtaResponse.h" // wouldn't take class #include using namespace std; /** Device Class represents a disk device, conforming to the TCG Enterprise standard */ class DtaDevEnterprise : public DtaDevOS { public: /** Constructor using an OS specific device descriptor. * @param devref reference to device is OS specific lexicon * */ DtaDevEnterprise(const char * devref); /** Default destructor, does nothing*/ ~DtaDevEnterprise(); /** Inform TPer of the communication propertied I wiah to use and * receive the TPer maximum values */ uint8_t properties(); /** Send a command to the device and wait for the response * @param cmd the DtaCommand object containg the command * @param response the DtaResonse object containing the response * @param protocol The security protocol number to use for the command */ uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01); /** return the communications ID to be used for sessions to this device */ uint16_t comID(); /** Change the SID password from it's MSID default * @param newpassword new password for SID */ uint8_t takeOwnership(char * newpassword); /** Change the passwords for the enabled Bandmasters and the Erasemaster * from the MSID default. * @param defaultPassword the MSID password * @param newPassword the nesw password to be set * */ uint8_t initLSPUsers(char * defaultPassword, char * newPassword); /** retrieve the MSID password */ uint8_t printDefaultPassword(); /** retrieve a single row from a table * @param table the UID of the table * @param startcol the starting column of data requested * @param endcol the ending column of the data requested */ uint8_t getTable(vector table, const char * startcol, const char * endcol); /** Set the SID password. * Requires special handling because password is not always hashed. * @param oldpassword current SID password * @param newpassword value password is to be changed to * @param hasholdpwd is the old password to be hashed before being added to the bytestream * @param hashnewpwd is the new password to be hashed before being added to the bytestream */ uint8_t setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1); /** set a single column in an object table * @param table the UID of the table * @param name the column name to be set * @param value data to be stored the the column */ uint8_t setTable(vector table, const char *name, vector value); /** set a single column in a table * @param table the UID of the table * @param name the column name to be set * @param value data to be stored the the column */ uint8_t setTable(vector table, const char *name, OPAL_TOKEN value); /** dummy code not implemented the the enterprise SSC */ uint8_t activateLockingSP(char * password); /** dummy code not implemented in teh enterprise SSC*/ uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); /** dummy code not implemented in teh enterprise SSC*/ uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); /** dummy code not implemented in teh enterprise SSC*/ uint8_t revertLockingSP(char * password, uint8_t keep = 0); /** get the UID or CPIN ID of a user from their character name*/ uint8_t getAuth4User(char * userid, uint8_t column, std::vector &userData); /** Enable a Bandmaster Not functional */ uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE); /** Primitive to set the MBRDone flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ uint8_t setMBRDone(uint8_t state, char * Admin1Password); /** Primitive to set the MBREnable flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ uint8_t setMBREnable(uint8_t state, char * Admin1Password); /** Set the password of a locking SP user. * @param password current password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ uint8_t setPassword(char * password, char * userid, char * newpassword); /** dummy code not implemented in the enterprise SSC*/ uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword); uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * password); /** dummy code not implemented in the enterprise SSC*/ uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password); /** Setup a locking range. Initialize a locking range, set it's start * LBA and length, initialize it as unlocked with locking disabled. * @param lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @param password Password of administrator */ uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** dummy code not implemented in the enterprise SSC*/ uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** List status of locking ranges. * @param password Password of administrator */ uint8_t listLockingRanges(char * password, int16_t rangeid); /** Change the active state of a locking range * @param lockingrange The number of the locking range (0 = global) * @param enabled enable (true) or disable (false) the lockingrange * @param password password of administrative authority for locking range */ uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password); /** Generate a new encryption key for a locking range. * @param lockingrange locking range number * @param password password of the locking administrative authority */ uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); uint8_t setBandsEnabled(int16_t lockingrange, char * password); /** Reset the TPER to its factory condition * ERASES ALL DATA! * @param password password of authority (SID or PSID) * @param PSID true or false is the authority the PSID * */ uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0); /** Erase a locking range * @param lockingrange The number of the locking range (0 = global) * @param password Password of administrative authority for locking range */ uint8_t eraseLockingRange(uint8_t lockingrange, char * password); /** Loads a disk image file to the shadow MBR table. * @param password the password for the administrative authority with access to the table * @param filename the filename of the disk image */ uint8_t loadPBA(char * password, char * filename); /** User command to prepare the device for management by sedutil. * Specific to the SSC that the device supports * @param password the password that is to be assigned to the SSC master entities */ uint8_t initialSetup(char * password); /** dummy code not implemented in the enterprise SSC*/ uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); /** Displays the identify and discovery 0 information */ void puke(); /** Dumps an object for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param objID the UID of the object to dump * */ uint8_t objDump(char *sp, char * auth, char *pass, char * objID); /** Issue any command to the drive for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param hexauth the authority ti use for the dump * @param pass the password for the suthority * @param hexinvokingUID caller of the method * @param hexmethod the method to call * @param hexparms the parameter list for the command * */ uint8_t rawCmd(char *sp, char *hexauth, char *pass, char *hexinvokingUID, char *hexmethod, char *hexparms); protected: uint8_t getDefaultPassword(); private: uint8_t getMaxRanges(char * password, uint16_t *maxRanges); uint8_t getMaxRangesOpal(char * password, uint16_t *maxRanges); }; sedutil-1.20.0/Common/DtaDevGeneric.cpp000066400000000000000000000101631410717517300176520ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4100) #endif #include "os.h" #include #include #include #include #include "DtaOptions.h" #include "DtaDevGeneric.h" #include "DtaHashPwd.h" #include "DtaEndianFixup.h" #include "DtaStructures.h" #include "DtaCommand.h" #include "DtaResponse.h" #include "DtaSession.h" #include "DtaHexDump.h" using namespace std; /** Class representing a disk device, this class is intended to be used when * it is not yet known if the device is OPAL compliant */ #define voidNOCODE(name, ...) void DtaDevGeneric::name(##__VA_ARGS__) { \ LOG(E) << "Generic Device class does not support function " << #name << std::endl; \ } #define uint8NOCODE(name, ...) uint8_t DtaDevGeneric::name(__VA_ARGS__) { \ LOG(E) << "Generic Device class does not support function " << #name << std::endl; \ return 0xff; \ } DtaDevGeneric::DtaDevGeneric(const char * devref) { DtaDevOS::init(devref); } DtaDevGeneric::~DtaDevGeneric() { } void DtaDevGeneric::init(const char * devref) { } uint8NOCODE(initialSetup, char *password) uint8NOCODE(configureLockingRange,uint8_t lockingrange, uint8_t enabled, char * password) uint8NOCODE(revertLockingSP,char * password, uint8_t keep) uint8NOCODE(setup_SUM, uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) uint8NOCODE(setPassword,char * password, char * userid, char * newpassword) uint8NOCODE(setNewPassword_SUM,char * password, char * userid, char * newpassword) uint8NOCODE(setMBREnable,uint8_t mbrstate, char * Admin1Password) uint8NOCODE(setMBRDone,uint8_t mbrstate, char * Admin1Password) uint8NOCODE(setLockingRange,uint8_t lockingrange, uint8_t lockingstate, char * Admin1Password) uint8NOCODE(setLockingRange_SUM, uint8_t lockingrange, uint8_t lockingstate, char * password) uint8NOCODE(setupLockingRange,uint8_t lockingrange, uint64_t start, uint64_t length, char * password) uint8NOCODE(listLockingRanges, char * password, int16_t rangeid) uint8NOCODE(setupLockingRange_SUM, uint8_t lockingrange, uint64_t start, uint64_t length, char * password) uint8NOCODE(rekeyLockingRange, uint8_t lockingrange, char * password) uint8NOCODE(setBandsEnabled, int16_t lockingrange, char * password) uint8NOCODE(enableUser,char * password, char * userid, OPAL_TOKEN status) uint8NOCODE(revertTPer,char * password, uint8_t PSID, uint8_t AdminSP) uint8NOCODE(eraseLockingRange,uint8_t lockingrange, char * password) uint8NOCODE(printDefaultPassword); uint8NOCODE(loadPBA,char * password, char * filename) uint8NOCODE(activateLockingSP,char * password) uint8NOCODE(activateLockingSP_SUM,uint8_t lockingrange, char * password) uint8NOCODE(eraseLockingRange_SUM, uint8_t lockingrange, char * password) uint8NOCODE(takeOwnership, char * newpassword) uint8NOCODE(setSIDPassword,char * oldpassword, char * newpassword, uint8_t hasholdpwd, uint8_t hashnewpwd) uint16_t DtaDevGeneric::comID() { LOG(E) << "Generic Device class does not support function " << "comID" << std::endl; return 0xff; } uint8NOCODE(exec,DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) uint8NOCODE(objDump,char *sp, char * auth, char *pass,char * objID) uint8NOCODE(rawCmd,char *sp, char * auth, char *pass,char *invoker, char *method, char *plist) #ifdef _MSC_VER #pragma warning(pop) #endif sedutil-1.20.0/Common/DtaDevGeneric.h000066400000000000000000000254571410717517300173330ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once class DtaCommand; class DtaSession; #include "os.h" #include "DtaDev.h" #include "DtaDevOS.h" #include "DtaStructures.h" #include using namespace std; /** Device Class representing an unknown type of disk device. * This device is used in determining if a disk supports a TCG Storage SSC. * Most of the functions in this class are implemented to return an error as * it is not known if the device supports a SSC * */ class DtaDevGeneric : public DtaDevOS { public: /** Constructor using an OS specific device descriptor. * @param devref reference to device is OS specific lexicon * */ DtaDevGeneric(const char * devref); /** Default constructor */ ~DtaDevGeneric(); /** OS specific initialization. * This function should perform the necessary authority and environment checking * to allow proper functioning of the program, open the device, perform an ATA * identify, add the fields from the identify response to the disk info structure * and if the device is an ATA device perform a call to Discovery0() to complete * the disk_info structure * @param devref character representation of the device is standard OS lexicon */ void init(const char * devref) ; /* sedutil.cpp */ /** User command to prepare the device for management by sedutil. * Specific to the SSC that the device supports * @param password the password that is to be assigned to the SSC master entities */ uint8_t initialSetup(char * password) ; /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. * @param lockingrange locking range number to enable * @param start LBA to start locking range * @param length length (in blocks) for locking range * @param Admin1Password admin1 password for TPer * @param password User password to set for locking range */ uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); /** Set the SID password. * Requires special handling because password is not always hashed. * @param oldpassword current SID password * @param newpassword value password is to be changed to * @param hasholdpwd is the old password to be hashed before being added to the bytestream * @param hashnewpwd is the new password to be hashed before being added to the bytestream */ uint8_t setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) ; /** Set the password of a locking SP user. * @param password current password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ uint8_t setPassword(char * password, char * userid, char * newpassword) ; /** Set the password of a locking SP user in Single User Mode. * @param password current user password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) ; /** Loads a disk image file to the shadow MBR table. * @param password the password for the administrative authority with access to the table * @param filename the filename of the disk image */ uint8_t loadPBA(char * password, char * filename) ; /** Change the locking state of a locking range * @param lockingrange The number of the locking range (0 = global) * @param lockingstate the locking state to set * @param Admin1Password password of administrative authority for locking range */ uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * Admin1Password) ; /** Change the locking state of a locking range in Single User Mode * @param lockingrange The number of the locking range (0 = global) * @param lockingstate the locking state to set * @param password password of user authority for the locking range */ uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password); /** Change the active state of a locking range * @param lockingrange The number of the locking range (0 = global) * @param enabled enable (true) or disable (false) the lockingrange * @param password password of administrative authority for locking range */ uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) ; /** Setup a locking range. Initialize a locking range, set it's start * LBA and length, initialize it as unlocked with locking disabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @paran password Password of administrator */ uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** Setup a locking range in Single User Mode. Initialize a locking range, * set it's start LBA and length, initialize it as unlocked with locking enabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @paran password Password of administrator */ uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** Primitive to set the MBRDone flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ /** List status of locking ranges. * @param password Password of administrator */ uint8_t listLockingRanges(char * password, int16_t rangeid); /** Generate a new encryption key for a locking range. * @param lockingrange locking range number * @param password password of the locking administrative authority */ uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); /** Enable bands using MSID. * @param lockingrange locking range number */ uint8_t setBandsEnabled(int16_t rangeid, char * password); uint8_t setMBRDone(uint8_t state, char * Admin1Password) ; /** Primitive to set the MBREnable flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ uint8_t setMBREnable(uint8_t state, char * Admin1Password) ; /** enable a locking sp user. * @param password password of locking sp administrative authority * @param userid the user to be enabled */ uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE) ; /** Enable locking on the device * @param password password of the admin sp SID authority */ uint8_t activateLockingSP(char * password) ; /** Enable locking on the device in Single User Mode * @param lockingrange locking range to activate in SUM * @param password password of the admin sp SID authority */ uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); /** Erase a Single User Mode locking range by calling the drive's erase method * @param lockingrange The Locking Range to erase * @param password The administrator password for the drive */ uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); /** Change the SID password from it's MSID default * @param newpassword new password for SID and locking SP admins */ uint8_t takeOwnership(char * newpassword) ; /** Reset the Locking SP to its factory default condition * ERASES ALL DATA! * @param password of Administrative user * @param keep true false for noerase function NOT WWORKING */ uint8_t revertLockingSP(char * password, uint8_t keep ) ; /** Reset the TPER to its factory condition * ERASES ALL DATA! * @param password password of authority (SID or PSID) * @param PSID true or false is the authority the PSID * */ uint8_t revertTPer(char * password, uint8_t PSID, uint8_t AdminSP ) ; /** Erase a locking range * @param lockingrange The number of the locking range (0 = global) * @param password Password of administrative authority for locking range */ virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password); /** Dumps an object for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param objID the UID of the object to dump */ uint8_t objDump(char *sp, char * auth, char *pass, char * objID) ; /** Issue any command to the drive for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param invoker caller of the method * @param method the method to call * @param plist the parameter list for the command * */ uint8_t rawCmd(char *sp, char * auth, char *pass, char *invoker, char *method, char *plist) ; /** Read MSID */ uint8_t printDefaultPassword(); /* DtaSession.cpp */ /** Send a command to the device and wait for the response * @param cmd the MswdCommand object containg the command * @param response the DtaResonse object containing the response * @param protocol The security protocol number to use for the command */ uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 1) ; /** return the communications ID to be used for sessions to this device */ uint16_t comID() ; }; sedutil-1.20.0/Common/DtaDevOpal.cpp000066400000000000000000001637771410717517300172150ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ /** Device class for Opal 2.0 SSC * also supports the Opal 1.0 SSC */ #include "os.h" #include #include #include #include #include "DtaDevOpal.h" #include "DtaHashPwd.h" #include "DtaEndianFixup.h" #include "DtaStructures.h" #include "DtaCommand.h" #include "DtaResponse.h" #include "DtaSession.h" #include "DtaHexDump.h" using namespace std; DtaDevOpal::DtaDevOpal() { } DtaDevOpal::~DtaDevOpal() { } void DtaDevOpal::init(const char * devref) { uint8_t lastRC; DtaDevOS::init(devref); if((lastRC = properties()) != 0) { LOG(E) << "Properties exchange failed";} } uint8_t DtaDevOpal::initialSetup(char * password) { LOG(D1) << "Entering initialSetup()"; uint8_t lastRC; if ((lastRC = takeOwnership(password)) != 0) { LOG(E) << "Initial setup failed - unable to take ownership"; return lastRC; } if ((lastRC = activateLockingSP(password)) != 0) { LOG(E) << "Initial setup failed - unable to activate LockingSP"; return lastRC; } if ((lastRC = configureLockingRange(0, DTA_DISABLELOCKING, password)) != 0) { LOG(E) << "Initial setup failed - unable to configure global locking range"; return lastRC; } if ((lastRC = setLockingRange(0, OPAL_LOCKINGSTATE::READWRITE, password)) != 0) { LOG(E) << "Initial setup failed - unable to set global locking range RW"; return lastRC; } if ((lastRC = setMBRDone(1, password)) != 0){ LOG(E) << "Initial setup failed - unable to Enable MBR shadow"; return lastRC; } if ((lastRC = setMBREnable(1, password)) != 0){ LOG(E) << "Initial setup failed - unable to Enable MBR shadow"; return lastRC; } LOG(I) << "Initial setup of TPer complete on " << dev; LOG(D1) << "Exiting initialSetup()"; return 0; } uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) { LOG(D1) << "Entering setup_SUM()"; uint8_t lastRC; char defaultPW[] = ""; //OPAL defines the default initial User password as 0x00 std::string userId; userId.append("User"); userId.append(std::to_string(lockingrange + 1)); //OPAL defines LR0 to User1, LR1 to User2, etc. //verify opal SUM support and status if (!disk_info.Locking || !disk_info.SingleUser) { LOG(E) << "Setup_SUM failed - this drive does not support LockingSP / SUM"; return DTAERROR_INVALID_COMMAND; } if (disk_info.Locking_lockingEnabled && !disk_info.SingleUser_any) { LOG(E) << "Setup_SUM failed - LockingSP has already been configured in standard mode."; return DTAERROR_INVALID_COMMAND; } //If locking not enabled, run initial setup flow if (!disk_info.Locking_lockingEnabled) { LOG(D1) << "LockingSP not enabled. Beginning initial setup flow."; if ((lastRC = takeOwnership(Admin1Password)) != 0) { LOG(E) << "Setup_SUM failed - unable to take ownership"; return lastRC; } if ((lastRC = activateLockingSP_SUM(lockingrange, Admin1Password)) != 0) { LOG(E) << "Setup_SUM failed - unable to activate LockingSP in SUM"; return lastRC; } if ((lastRC = setupLockingRange_SUM(lockingrange, start, length, defaultPW)) != 0) { LOG(E) << "Setup_SUM failed - unable to setup locking range " << lockingrange << "(" << start << "," << length << ")"; return lastRC; } } if ((lastRC = eraseLockingRange_SUM(lockingrange, Admin1Password)) != 0) { LOG(E) << "Setup_SUM failed - unable to erase locking range"; return lastRC; } //verify that locking range covers correct LBAs lrStatus_t lrStatus; if ((lrStatus = getLockingRange_status(lockingrange, Admin1Password)).command_status != 0) { LOG(E) << "Setup_SUM failed - unable to query locking range start/size"; return lrStatus.command_status; } if (start != lrStatus.start || length != lrStatus.size) { LOG(D1) << "Incorrect Locking Range " << lockingrange << " start/size. Attempting to correct..."; if ((lastRC = setupLockingRange_SUM(lockingrange, start, length, defaultPW)) != 0) { LOG(E) << "Setup_SUM failed - unable to setup locking range " << lockingrange << "(" << start << "," << length << ")"; return lastRC; } LOG(D1) << "Locking Range " << lockingrange << " start/size corrected."; } //enable and set new password for locking range if ((lastRC = setLockingRange_SUM(lockingrange, OPAL_LOCKINGSTATE::READWRITE, defaultPW)) != 0) { LOG(E) << "Setup_SUM failed - unable to enable locking range"; return lastRC; } if ((lastRC = setNewPassword_SUM(defaultPW, (char *)userId.c_str(), password)) != 0) { LOG(E) << "Setup_SUM failed - unable to set new locking range password"; return lastRC; } LOG(I) << "Setup of SUM complete on " << dev; LOG(D1) << "Exiting setup_SUM()"; return 0; } DtaDevOpal::lrStatus_t DtaDevOpal::getLockingRange_status(uint8_t lockingrange, char * password) { uint8_t lastRC; lrStatus_t lrStatus; LOG(D1) << "Entering DtaDevOpal:getLockingRange_status()"; vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; lrStatus.command_status = DTAERROR_OBJECT_CREATE_FAILED; return lrStatus; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; lrStatus.command_status = lastRC; return lrStatus; } if (0 != lockingrange) { LR[8] = lockingrange & 0xff; LR[6] = 0x03; // non global ranges are 00000802000300nn } if ((lastRC = getTable(LR, _OPAL_TOKEN::RANGESTART, _OPAL_TOKEN::WRITELOCKED)) != 0) { delete session; lrStatus.command_status = lastRC; return lrStatus; } if (response.getTokenCount() < 24) { LOG(E) << "locking range getTable command did not return enough data"; delete session; lrStatus.command_status = DTAERROR_NO_LOCKING_INFO; return lrStatus; } lrStatus.command_status = 0; lrStatus.lockingrange_num = lockingrange; lrStatus.start = response.getUint64(4); lrStatus.size = response.getUint64(8); lrStatus.RLKEna = (response.getUint8(12) != 0); lrStatus.WLKEna = (response.getUint8(16) != 0); lrStatus.RLocked = (response.getUint8(20) != 0); lrStatus.WLocked = (response.getUint8(24) != 0); LOG(D1) << "Locking Range " << lockingrange << " Begin: " << lrStatus.start << " Length: " << lrStatus.size << " RLKEna: " << lrStatus.RLKEna << " WLKEna: " << lrStatus.WLKEna << " RLocked: " << lrStatus.RLocked << " WLocked: " << lrStatus.WLocked; delete session; LOG(D1) << "Exiting DtaDevOpal:getLockingRange_status()"; return lrStatus; } uint8_t DtaDevOpal::listLockingRanges(char * password, int16_t rangeid) { uint8_t lastRC; LOG(D1) << "Entering DtaDevOpal:listLockingRanges()" << rangeid; vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } vector table; table.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_LOCKING_INFO_TABLE][i]); } if ((lastRC = getTable(table, _OPAL_TOKEN::MAXRANGES, _OPAL_TOKEN::MAXRANGES)) != 0) { delete session; return lastRC; } if (response.tokenIs(4) != _OPAL_TOKEN::DTA_TOKENID_UINT) { LOG(E) << "Unable to determine number of ranges "; delete session; return DTAERROR_NO_LOCKING_INFO; } LOG(I) << "Locking Range Configuration for " << dev; uint32_t numRanges = response.getUint32(4) + 1; for (uint32_t i = 0; i < numRanges; i++){ if(0 != i) LR[8] = i & 0xff; if ((lastRC = getTable(LR, _OPAL_TOKEN::RANGESTART, _OPAL_TOKEN::WRITELOCKED)) != 0) { delete session; return lastRC; } LR[6] = 0x03; // non global ranges are 00000802000300nn LOG(I) << "LR" << i << " Begin " << response.getUint64(4) << " for " << response.getUint64(8); LOG(I) << " RLKEna =" << (response.getUint8(12) ? " Y " : " N ") << " WLKEna =" << (response.getUint8(16) ? " Y " : " N ") << " RLocked =" << (response.getUint8(20) ? " Y " : " N ") << " WLocked =" << (response.getUint8(24) ? " Y " : " N "); } delete session; LOG(D1) << "Exiting DtaDevOpal:listLockingRanges()"; return 0; } uint8_t DtaDevOpal::setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevOpal:setupLockingRange()"; if (lockingrange < 1) { LOG(E) << "global locking range cannot be changed"; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } LR[6] = 0x03; LR[8] = lockingrange; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(LR); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::RANGESTART); set->addToken(start); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::RANGELENGTH); set->addToken(length); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "setupLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; if ((lastRC = rekeyLockingRange(lockingrange, password)) != 0) { LOG(E) << "setupLockingRange Unable to reKey Locking range -- Possible security issue "; return lastRC; } LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << " for " << length << " blocks configured as unlocked range"; LOG(D1) << "Exiting DtaDevOpal:setupLockingRange()"; return 0; } uint8_t DtaDevOpal::setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevOpal:setupLockingRange_SUM()"; if (lockingrange < 1) { LOG(E) << "global locking range cannot be changed"; return DTAERROR_UNSUPORTED_LOCKING_RANGE; } vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } LR[6] = 0x03; LR[8] = lockingrange; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } vector auth; auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 7; i++) { auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); } auth.push_back(lockingrange+1); if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { LOG(E) << "Error starting session. Did you provide the correct user password? (GlobalRange = User1; Range1 = User2, etc.)"; delete session; return lastRC; } DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(LR); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::RANGESTART); set->addToken(start); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::RANGELENGTH); set->addToken(length); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_TRUE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_TRUE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKED); set->addToken(OPAL_TOKEN::OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "setupLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; if ((lastRC = rekeyLockingRange_SUM(LR, auth, password)) != 0) { LOG(E) << "setupLockingRange Unable to reKey Locking range -- Possible security issue "; return lastRC; } LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << " for " << length << " blocks configured as LOCKED range"; LOG(D1) << "Exiting DtaDevOpal:setupLockingRange_SUM()"; return 0; } uint8_t DtaDevOpal::configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevOpal::configureLockingRange()"; vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange != 0) { LR[6] = 0x03; LR[8] = lockingrange; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(LR); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKENABLED); set->addToken((enabled & DTA_READLOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKENABLED); set->addToken((enabled & DTA_WRITELOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "configureLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; LOG(I) << "LockingRange" << (uint16_t) lockingrange << (enabled ? " enabled " : " disabled ") << ((enabled & DTA_READLOCKINGENABLED) ? "ReadLocking" : "") << ((enabled == (DTA_WRITELOCKINGENABLED | DTA_READLOCKINGENABLED)) ? "," : "") << ((enabled & DTA_WRITELOCKINGENABLED) ? "WriteLocking" : ""); LOG(D1) << "Exiting DtaDevOpal::configureLockingRange()"; return 0; } uint8_t DtaDevOpal::rekeyLockingRange(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevOpal::rekeyLockingRange()"; uint8_t lastRC; vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange != 0) { LR[6] = 0x03; LR[8] = lockingrange; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } if ((lastRC = getTable(LR, OPAL_TOKEN::ACTIVEKEY, OPAL_TOKEN::ACTIVEKEY)) != 0) { delete session; return lastRC; } DtaCommand *rekey = new DtaCommand(); if (NULL == rekey) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); rekey->changeInvokingUid(response.getRawToken(4)); rekey->addToken(OPAL_TOKEN::STARTLIST); rekey->addToken(OPAL_TOKEN::ENDLIST); rekey->complete(); if ((lastRC = session->sendCommand(rekey, response)) != 0) { LOG(E) << "rekeyLockingRange Failed "; delete rekey; delete session; return lastRC; } delete rekey; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " reKeyed "; LOG(D1) << "Exiting DtaDevOpal::rekeyLockingRange()"; return 0; } uint8_t DtaDevOpal::rekeyLockingRange_SUM(vector LR, vector UID, char * password) { LOG(D1) << "Entering DtaDevOpal::rekeyLockingRange_SUM()"; uint8_t lastRC; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, UID)) != 0) { delete session; return lastRC; } if ((lastRC = getTable(LR, OPAL_TOKEN::ACTIVEKEY, OPAL_TOKEN::ACTIVEKEY)) != 0) { delete session; return lastRC; } DtaCommand *rekey = new DtaCommand(); if (NULL == rekey) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); rekey->changeInvokingUid(response.getRawToken(4)); rekey->addToken(OPAL_TOKEN::STARTLIST); rekey->addToken(OPAL_TOKEN::ENDLIST); rekey->complete(); if ((lastRC = session->sendCommand(rekey, response)) != 0) { LOG(E) << "rekeyLockingRange_SUM Failed "; delete rekey; delete session; return lastRC; } delete rekey; delete session; LOG(I) << "LockingRange reKeyed "; LOG(D1) << "Exiting DtaDevOpal::rekeyLockingRange_SUM()"; return 0; } uint8_t DtaDevOpal::setBandsEnabled(int16_t lockingrange, char * password) { if (password == NULL) { LOG(D4) << "Password is NULL"; } // unreferenced formal paramater LOG(D1) << "Entering DtaDevOpal::setBandsEnabled()" << lockingrange << " " << dev; LOG(I) << "setBandsEnabled is not implemented. It is not part of the Opal SSC "; LOG(D1) << "Exiting DtaDevOpal::setBandsEnabled()"; return 0; } uint8_t DtaDevOpal::revertLockingSP(char * password, uint8_t keep) { LOG(D1) << "Entering DtaDevOpal::revertLockingSP() keep = " << (uint16_t) keep; uint8_t lastRC; vector keepGlobalLocking; keepGlobalLocking.push_back(0x83); keepGlobalLocking.push_back(0x06); keepGlobalLocking.push_back(0x00); keepGlobalLocking.push_back(0x00); DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Create session object failed"; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Create session object failed"; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete cmd; delete session; LOG(E) << "Start session failed"; return lastRC; } cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); cmd->addToken(OPAL_TOKEN::STARTLIST); if (keep) { cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken(keepGlobalLocking); cmd->addToken(OPAL_TOKEN::OPAL_TRUE); cmd->addToken(OPAL_TOKEN::ENDNAME); } cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { LOG(E) << "Command failed"; delete cmd; delete session; return lastRC; } // empty list returned so rely on method status LOG(I) << "Revert LockingSP complete"; session->expectAbort(); delete session; LOG(D1) << "Exiting DtaDevOpal::revertLockingSP()"; return 0; } uint8_t DtaDevOpal::eraseLockingRange(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevOpal::eraseLockingRange()" << lockingrange << " " << dev; if (password == NULL) { LOG(D4) << "Referencing formal parameters " << lockingrange; } LOG(I) << "eraseLockingRange is not implemented. It is not part of the Opal SSC "; LOG(D1) << "Exiting DtaDevOpal::eraseLockingRange()"; return 0; } uint8_t DtaDevOpal::getAuth4User(char * userid, uint8_t uidorcpin, std::vector &userData) { LOG(D1) << "Entering DtaDevOpal::getAuth4User()"; userData.clear(); userData. push_back(OPAL_SHORT_ATOM::BYTESTRING8); userData.push_back(0x00); userData.push_back(0x00); userData.push_back(0x00); if ((0 != uidorcpin) && (10 != uidorcpin)) { LOG(E) << "Invalid Userid data requested" << (uint16_t)uidorcpin; return DTAERROR_INVALID_PARAMETER; } if(uidorcpin) userData.push_back(0x0b); else userData.push_back(0x09); if (!memcmp("User", userid, 4)) { userData.push_back(0x00); userData.push_back(0x03); userData.push_back(0x00); userData.push_back(atoi(&userid[4]) &0xff ); } else { if (!memcmp("Admin", userid, 5)) { userData.push_back(0x00); userData.push_back(0x01); userData.push_back(0x00); userData.push_back(atoi(&userid[5]) & 0xff ); } else { LOG(E) << "Invalid Userid " << userid; userData.clear(); return DTAERROR_INVALID_PARAMETER; } } LOG(D1) << "Exiting DtaDevOpal::getAuth4User()"; return 0; } uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpassword) { LOG(D1) << "Entering DtaDevOpal::setPassword" ; uint8_t lastRC; std::vector userCPIN, hash; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } if ((lastRC = getAuth4User(userid, 10, userCPIN)) != 0) { LOG(E) << "Unable to find user " << userid << " in Authority Table"; delete session; return lastRC; } DtaHashPwd(hash, newpassword, this); if ((lastRC = setTable(userCPIN, OPAL_TOKEN::PIN, hash)) != 0) { LOG(E) << "Unable to set user " << userid << " new password "; delete session; return lastRC; } LOG(I) << userid << " password changed"; delete session; LOG(D1) << "Exiting DtaDevOpal::setPassword()"; return 0; } uint8_t DtaDevOpal::setNewPassword_SUM(char * password, char * userid, char * newpassword) { LOG(D1) << "Entering DtaDevOpal::setNewPassword_SUM"; uint8_t lastRC; std::vector userCPIN, hash; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } vector auth; if (!memcmp("Admin", userid, 5)) { auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 7; i++) { auth.push_back(OPALUID[OPAL_UID::OPAL_ADMIN1_UID][i]); } auth.push_back((uint8_t)atoi(&userid[5])); } else if (!memcmp("User", userid, 4)) { auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 7; i++) { auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); } auth.push_back((uint8_t)atoi(&userid[4])); } else { LOG(E) << "Invalid userid \"" << userid << "\"specified for setNewPassword_SUM"; delete session; return DTAERROR_INVALID_PARAMETER; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { delete session; return lastRC; } if ((lastRC = getAuth4User(userid, 10, userCPIN)) != 0) { LOG(E) << "Unable to find user " << userid << " in Authority Table"; delete session; return lastRC; } DtaHashPwd(hash, newpassword, this); if ((lastRC = setTable(userCPIN, OPAL_TOKEN::PIN, hash)) != 0) { LOG(E) << "Unable to set user " << userid << " new password "; delete session; return lastRC; } LOG(I) << userid << " password changed"; delete session; LOG(D1) << "Exiting DtaDevOpal::setNewPassword_SUM()"; return 0; } uint8_t DtaDevOpal::setMBREnable(uint8_t mbrstate, char * Admin1Password) { LOG(D1) << "Entering DtaDevOpal::setMBREnable"; uint8_t lastRC; // set MBRDone before changing MBREnable so the PBA isn't presented if ((lastRC = setMBRDone(1, Admin1Password)) != 0){ LOG(E) << "unable to set MBRDone"; return lastRC; } if (mbrstate) { if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRENABLE, OPAL_TOKEN::OPAL_TRUE, Admin1Password, NULL)) != 0) { LOG(E) << "Unable to set setMBREnable on"; return lastRC; } else { LOG(I) << "MBREnable set on "; } } else { if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRENABLE, OPAL_TOKEN::OPAL_FALSE, Admin1Password, NULL)) != 0) { LOG(E) << "Unable to set setMBREnable off"; return lastRC; } else { LOG(I) << "MBREnable set off "; } } LOG(D1) << "Exiting DtaDevOpal::setMBREnable"; return 0; } uint8_t DtaDevOpal::setMBRDone(uint8_t mbrstate, char * Admin1Password) { LOG(D1) << "Entering DtaDevOpal::setMBRDone"; uint8_t lastRC; if (mbrstate) { if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRDONE, OPAL_TOKEN::OPAL_TRUE, Admin1Password, NULL)) != 0) { LOG(E) << "Unable to set setMBRDone on"; return lastRC; } else { LOG(I) << "MBRDone set on "; } } else { if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRDONE, OPAL_TOKEN::OPAL_FALSE, Admin1Password, NULL)) != 0) { LOG(E) << "Unable to set setMBRDone off"; return lastRC; } else { LOG(I) << "MBRDone set off "; } } LOG(D1) << "Exiting DtaDevOpal::setMBRDone"; return 0; } uint8_t DtaDevOpal::setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * Admin1Password) { uint8_t lastRC; uint8_t archiveuser = 0; OPAL_TOKEN readlocked, writelocked; const char *msg; LOG(D1) << "Entering DtaDevOpal::setLockingRange"; switch (lockingstate) { case OPAL_LOCKINGSTATE::READWRITE: readlocked = writelocked = OPAL_TOKEN::OPAL_FALSE; msg = "RW"; break; case OPAL_LOCKINGSTATE::ARCHIVEUNLOCKED: archiveuser = 1; case OPAL_LOCKINGSTATE::READONLY: readlocked = OPAL_TOKEN::OPAL_FALSE; writelocked = OPAL_TOKEN::OPAL_TRUE; msg = "RO"; break; case OPAL_LOCKINGSTATE::ARCHIVELOCKED: archiveuser = 1; case OPAL_LOCKINGSTATE::LOCKED: readlocked = writelocked = OPAL_TOKEN::OPAL_TRUE; msg = "LK"; break; default: LOG(E) << "Invalid locking state for setLockingRange"; return DTAERROR_INVALID_PARAMETER; } vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange != 0) { LR[6] = 0x03; LR[8] = lockingrange; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, Admin1Password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(LR); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKED); set->addToken(readlocked); set->addToken(OPAL_TOKEN::ENDNAME); if (!archiveuser) { set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKED); set->addToken(writelocked); set->addToken(OPAL_TOKEN::ENDNAME); } set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "setLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " set to " << msg; LOG(D1) << "Exiting DtaDevOpal::setLockingRange"; return 0; } uint8_t DtaDevOpal::setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password) { uint8_t lastRC; OPAL_TOKEN readlocked, writelocked; const char *msg; LOG(D1) << "Entering DtaDevOpal::setLockingRange_SUM"; switch (lockingstate) { case OPAL_LOCKINGSTATE::READWRITE: readlocked = writelocked = OPAL_TOKEN::OPAL_FALSE; msg = "RW"; break; case OPAL_LOCKINGSTATE::READONLY: readlocked = OPAL_TOKEN::OPAL_FALSE; writelocked = OPAL_TOKEN::OPAL_TRUE; msg = "RO"; break; case OPAL_LOCKINGSTATE::LOCKED: readlocked = writelocked = OPAL_TOKEN::OPAL_TRUE; msg = "LK"; break; default: LOG(E) << "Invalid locking state for setLockingRange"; return DTAERROR_INVALID_PARAMETER; } vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange != 0) { LR[6] = 0x03; LR[8] = lockingrange; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } vector auth; auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 7; i++) { auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); } auth.push_back(lockingrange+1); if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { LOG(E) << "Error starting session. Did you provide the correct user password? (GlobalRange = User1; Range1 = User2, etc.)"; delete session; return lastRC; } DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(LR); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); set->addToken(OPAL_TOKEN::STARTLIST); //enable locking on the range to enforce lock state set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_TRUE); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKENABLED); set->addToken(OPAL_TOKEN::OPAL_TRUE); set->addToken(OPAL_TOKEN::ENDNAME); //set read/write locked set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::READLOCKED); set->addToken(readlocked); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::WRITELOCKED); set->addToken(writelocked); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "setLockingRange Failed "; delete set; delete session; return lastRC; } delete set; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " set to " << msg; LOG(D1) << "Exiting DtaDevOpal::setLockingRange_SUM"; return 0; } uint8_t DtaDevOpal::setLockingSPvalue(OPAL_UID table_uid, OPAL_TOKEN name, OPAL_TOKEN value,char * password, char * msg) { LOG(D1) << "Entering DtaDevOpal::setLockingSPvalue"; uint8_t lastRC; vector table; table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[table_uid][i]); } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } if ((lastRC = setTable(table, name, value)) != 0) { LOG(E) << "Unable to update table"; delete session; return lastRC; } if (NULL != msg) { LOG(I) << msg; } delete session; LOG(D1) << "Exiting DtaDevOpal::setLockingSPvalue()"; return 0; } uint8_t DtaDevOpal::enableUser(char * password, char * userid, OPAL_TOKEN status) { LOG(D1) << "Entering DtaDevOpal::enableUser"; uint8_t lastRC; vector userUID; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } if ((lastRC = getAuth4User(userid, 0, userUID)) != 0) { LOG(E) << "Unable to find user " << userid << " in Authority Table"; delete session; return lastRC; } if ((lastRC = setTable(userUID, (OPAL_TOKEN)0x05, status)) != 0) { LOG(E) << "Unable to enable user " << userid; delete session; return lastRC; } LOG(I) << userid << " has been enabled "; delete session; LOG(D1) << "Exiting DtaDevOpal::enableUser()"; return 0; } uint8_t DtaDevOpal::revertTPer(char * password, uint8_t PSID, uint8_t AdminSP) { LOG(D1) << "Entering DtaDevOpal::revertTPer() " << AdminSP; uint8_t lastRC; DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } OPAL_UID uid = OPAL_UID::OPAL_SID_UID; if (PSID) { session->dontHashPwd(); // PSID pwd should be passed as entered uid = OPAL_UID::OPAL_PSID_UID; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { delete cmd; delete session; return lastRC; } cmd->reset(OPAL_UID::OPAL_ADMINSP_UID, OPAL_METHOD::REVERT); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); session->expectAbort(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "revertTper completed successfully"; delete cmd; delete session; LOG(D1) << "Exiting DtaDevOpal::revertTPer()"; return 0; } uint8_t DtaDevOpal::loadPBA(char * password, char * filename) { LOG(D1) << "Entering DtaDevOpal::loadPBAimage()" << filename << " " << dev; uint8_t lastRC; uint32_t blockSize; uint32_t filepos = 0; uint32_t eofpos; ifstream pbafile; (MAX_BUFFER_LENGTH > tperMaxPacket) ? blockSize = tperMaxPacket : blockSize = MAX_BUFFER_LENGTH; if (blockSize > (tperMaxToken - 4)) blockSize = tperMaxToken - 4; vector buffer, lengthtoken; blockSize -= sizeof(OPALHeader) + 50; // packet overhead buffer.resize(blockSize); pbafile.open(filename, ios::in | ios::binary); if (!pbafile) { LOG(E) << "Unable to open PBA image file " << filename; return DTAERROR_OPEN_ERR; } pbafile.seekg(0, pbafile.end); eofpos = (uint32_t) pbafile.tellg(); pbafile.seekg(0, pbafile.beg); DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete cmd; delete session; pbafile.close(); return lastRC; } LOG(I) << "Writing PBA to " << dev; while (!pbafile.eof()) { if (eofpos == filepos) break; if ((eofpos - filepos) < blockSize) { blockSize = eofpos - filepos; // handle a short last block buffer.resize(blockSize); } lengthtoken.clear(); lengthtoken.push_back(0xe2); lengthtoken.push_back((uint8_t) ((blockSize >> 16) & 0x000000ff)); lengthtoken.push_back((uint8_t)((blockSize >> 8) & 0x000000ff)); lengthtoken.push_back((uint8_t)(blockSize & 0x000000ff)); pbafile.read((char *)buffer.data(), blockSize); cmd->reset(OPAL_UID::OPAL_MBR, OPAL_METHOD::SET); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken(OPAL_TOKEN::WHERE); cmd->addToken(filepos); cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken(OPAL_TOKEN::VALUES); cmd->addToken(lengthtoken); cmd->addToken(buffer); cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; pbafile.close(); return lastRC; } filepos += blockSize; cout << filepos << " of " << eofpos << " " << (uint16_t) (((float)filepos/(float)eofpos) * 100) << "% blk=" << blockSize << " \r"; } cout << "\n"; delete cmd; delete session; pbafile.close(); LOG(I) << "PBA image " << filename << " written to " << dev; LOG(D1) << "Exiting DtaDevOpal::loadPBAimage()"; return 0; } uint8_t DtaDevOpal::activateLockingSP(char * password) { LOG(D1) << "Entering DtaDevOpal::activateLockingSP()"; uint8_t lastRC; vector table; table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGSP_UID][i]); } DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, OPAL_UID::OPAL_SID_UID)) != 0) { delete cmd; delete session; return lastRC; } if ((lastRC = getTable(table, 0x06, 0x06)) != 0) { LOG(E) << "Unable to determine LockingSP Lifecycle state"; delete cmd; delete session; return lastRC; } if ((0x06 != response.getUint8(3)) || // getlifecycle (0x08 != response.getUint8(4))) // Manufactured-Inactive { LOG(E) << "Locking SP lifecycle is not Manufactured-Inactive"; delete cmd; delete session; return DTAERROR_INVALID_LIFECYCLE; } cmd->reset(OPAL_UID::OPAL_LOCKINGSP_UID, OPAL_METHOD::ACTIVATE); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "Locking SP Activate Complete"; delete cmd; delete session; LOG(D1) << "Exiting DtaDevOpal::activatLockingSP()"; return 0; } uint8_t DtaDevOpal::activateLockingSP_SUM(uint8_t lockingrange, char * password) { LOG(D1) << "Entering DtaDevOpal::activateLockingSP_SUM()"; uint8_t lastRC; vector table; table.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGSP_UID][i]); } vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange > 0) { LR[6] = 0x03; LR[8] = lockingrange; } DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, OPAL_UID::OPAL_SID_UID)) != 0) { LOG(E) << "session->start failed with code " << lastRC; delete cmd; delete session; return lastRC; } if ((lastRC = getTable(table, 0x06, 0x06)) != 0) { LOG(E) << "Unable to determine LockingSP Lifecycle state"; delete cmd; delete session; return lastRC; } if ((0x06 != response.getUint8(3)) || // getlifecycle (0x08 != response.getUint8(4))) // Manufactured-Inactive { LOG(E) << "Locking SP lifecycle is not Manufactured-Inactive"; delete cmd; delete session; return DTAERROR_INVALID_LIFECYCLE; } /*if (!disk_info.SingleUser) { LOG(E) << "This Locking SP does not support Single User Mode"; delete cmd; delete session; return DTAERROR_INVALID_COMMAND; }*/ cmd->reset(OPAL_UID::OPAL_LOCKINGSP_UID, OPAL_METHOD::ACTIVATE); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::STARTNAME); //SingleUserModeSelectionList parameter cmd->addToken(OPAL_SHORT_ATOM::UINT_3); cmd->addToken(OPAL_TINY_ATOM::UINT_06); cmd->addToken(OPAL_TINY_ATOM::UINT_00); cmd->addToken(OPAL_TINY_ATOM::UINT_00); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(LR); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { LOG(E) << "session->sendCommand failed with code " << lastRC; delete cmd; delete session; return lastRC; } disk_info.Locking_lockingEnabled = 1; LOG(I) << "Locking SP Activate Complete for single User" << (lockingrange+1) << " on locking range " << (int)lockingrange; delete cmd; delete session; LOG(D1) << "Exiting DtaDevOpal::activateLockingSP_SUM()"; return 0; } uint8_t DtaDevOpal::eraseLockingRange_SUM(uint8_t lockingrange, char * password) { uint8_t lastRC; LOG(D1) << "Entering DtaDevOpal::eraseLockingRange_SUM"; vector LR; LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); } if (lockingrange != 0) { LR[6] = 0x03; LR[8] = lockingrange; } session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { delete session; return lastRC; } DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::ERASE); cmd->changeInvokingUid(LR); cmd->addToken(OPAL_TOKEN::STARTLIST); cmd->addToken(OPAL_TOKEN::ENDLIST); cmd->complete(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { LOG(E) << "setLockingRange Failed "; delete cmd; delete session; return lastRC; } delete cmd; delete session; LOG(I) << "LockingRange" << (uint16_t)lockingrange << " erased"; LOG(D1) << "Exiting DtaDevOpal::eraseLockingRange_SUM"; return 0; } uint8_t DtaDevOpal::takeOwnership(char * newpassword) { LOG(D1) << "Entering DtaDevOpal::takeOwnership()"; uint8_t lastRC; if ((lastRC = getDefaultPassword()) != 0) { LOG(E) << "Unable to read MSID password "; return lastRC; } if ((lastRC = setSIDPassword((char *)response.getString(4).c_str(), newpassword, 0)) != 0) { LOG(E) << "takeOwnership failed"; return lastRC; } LOG(I) << "takeOwnership complete"; LOG(D1) << "Exiting takeOwnership()"; return 0; } uint8_t DtaDevOpal::getDefaultPassword() { LOG(D1) << "Entering DtaDevOpal::getDefaultPassword()"; uint8_t lastRC; vector hash; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID)) != 0) { LOG(E) << "Unable to start Unauthenticated session " << dev; delete session; return lastRC; } vector table; table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_MSID][i]); } if ((lastRC = getTable(table, PIN, PIN)) != 0) { delete session; return lastRC; } delete session; LOG(D1) << "Exiting getDefaultPassword()"; return 0; } uint8_t DtaDevOpal::printDefaultPassword() { const uint8_t rc = getDefaultPassword(); if (rc) { LOG(E) << "unable to read MSID password"; return rc; } string defaultPassword = response.getString(4); fprintf(stdout, "MSID: %s\n", (char *)defaultPassword.c_str()); return 0; } uint8_t DtaDevOpal::setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd, uint8_t hashnewpwd) { vector hash, table; LOG(D1) << "Entering DtaDevOpal::setSIDPassword()"; uint8_t lastRC; session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } if (!hasholdpwd) session->dontHashPwd(); if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, oldpassword, OPAL_UID::OPAL_SID_UID)) != 0) { delete session; return lastRC; } table.clear(); table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_SID][i]); } hash.clear(); if (hashnewpwd) { DtaHashPwd(hash, newpassword, this); } else { hash.push_back(0xd0); hash.push_back((uint8_t)strnlen(newpassword, 255)); for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) { hash.push_back(newpassword[i]); } } if ((lastRC = setTable(table, OPAL_TOKEN::PIN, hash)) != 0) { LOG(E) << "Unable to set new SID password "; delete session; return lastRC; } delete session; LOG(D1) << "Exiting DtaDevOpal::setSIDPassword()"; return 0; } uint8_t DtaDevOpal::setTable(vector table, OPAL_TOKEN name, OPAL_TOKEN value) { vector token; token.push_back((uint8_t) value); return(setTable(table, name, token)); } uint8_t DtaDevOpal::setTable(vector table, OPAL_TOKEN name, vector value) { LOG(D1) << "Entering DtaDevOpal::setTable"; uint8_t lastRC; DtaCommand *set = new DtaCommand(); if (NULL == set) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); set->changeInvokingUid(table); set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(OPAL_TOKEN::VALUES); // "values" set->addToken(OPAL_TOKEN::STARTLIST); set->addToken(OPAL_TOKEN::STARTNAME); set->addToken(name); set->addToken(value); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->addToken(OPAL_TOKEN::ENDNAME); set->addToken(OPAL_TOKEN::ENDLIST); set->complete(); if ((lastRC = session->sendCommand(set, response)) != 0) { LOG(E) << "Set Failed "; delete set; return lastRC; } delete set; LOG(D1) << "Leaving DtaDevOpal::setTable"; return 0; } uint8_t DtaDevOpal::getTable(vector table, uint16_t startcol, uint16_t endcol) { LOG(D1) << "Entering DtaDevOpal::getTable"; uint8_t lastRC; DtaCommand *get = new DtaCommand(); if (NULL == get) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GET); get->changeInvokingUid(table); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTNAME); get->addToken(OPAL_TOKEN::STARTCOLUMN); get->addToken(startcol); get->addToken(OPAL_TOKEN::ENDNAME); get->addToken(OPAL_TOKEN::STARTNAME); get->addToken(OPAL_TOKEN::ENDCOLUMN); get->addToken(endcol); get->addToken(OPAL_TOKEN::ENDNAME); get->addToken(OPAL_TOKEN::ENDLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->complete(); if ((lastRC = session->sendCommand(get, response)) != 0) { delete get; return lastRC; } delete get; return 0; } uint8_t DtaDevOpal::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) { uint8_t lastRC; OPALHeader * hdr = (OPALHeader *) cmd->getCmdBuffer(); LOG(D3) << endl << "Dumping command buffer"; IFLOG(D3) DtaHexDump(cmd->getCmdBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); if((lastRC = sendCmd(IF_SEND, protocol, comID(), cmd->getCmdBuffer(), cmd->outputBufferSize())) != 0) { LOG(E) << "Command failed on send " << (uint16_t) lastRC; return lastRC; } hdr = (OPALHeader *) cmd->getRespBuffer(); do { osmsSleep(25); memset(cmd->getRespBuffer(), 0, MIN_BUFFER_LENGTH); lastRC = sendCmd(IF_RECV, protocol, comID(), cmd->getRespBuffer(), MIN_BUFFER_LENGTH); } while ((0 != hdr->cp.outstandingData) && (0 == hdr->cp.minTransfer)); LOG(D3) << std::endl << "Dumping reply buffer"; IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); if (0 != lastRC) { LOG(E) << "Command failed on recv" << (uint16_t) lastRC; return lastRC; } resp.init(cmd->getRespBuffer()); return 0; } uint8_t DtaDevOpal::properties() { LOG(D1) << "Entering DtaDevOpal::properties()"; uint8_t lastRC; session = new DtaSession(this); // use the session IO without starting a session if (NULL == session) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } DtaCommand *props = new DtaCommand(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::PROPERTIES); if (NULL == props) { LOG(E) << "Unable to create command object "; delete session; return DTAERROR_OBJECT_CREATE_FAILED; } props->addToken(OPAL_TOKEN::STARTLIST); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken(OPAL_TOKEN::HOSTPROPERTIES); props->addToken(OPAL_TOKEN::STARTLIST); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxComPacketSize"); props->addToken(2048); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxPacketSize"); props->addToken(2028); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxIndTokenSize"); props->addToken(1992); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxPackets"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxSubpackets"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::STARTNAME); props->addToken("MaxMethods"); props->addToken(1); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->complete(); if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { delete props; return lastRC; } disk_info.Properties = 1; delete props; for (uint32_t i = 0; i < propertiesResponse.getTokenCount(); i++) { if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING != propertiesResponse.tokenIs(i + 1)) break; else if(!strcasecmp("MaxComPacketSize",propertiesResponse.getString(i + 1).c_str())) tperMaxPacket = propertiesResponse.getUint32(i + 2); else if (!strcasecmp("MaxIndTokenSize", propertiesResponse.getString(i + 1).c_str())) { tperMaxToken = propertiesResponse.getUint32(i + 2); break; } i += 2; } } LOG(D1) << "Leaving DtaDevOpal::properties()"; return 0; } void DtaDevOpal::puke() { LOG(D1) << "Entering DtaDevOpal::puke()"; DtaDev::puke(); if (disk_info.Properties) { cout << std::endl << "TPer Properties: "; for (uint32_t i = 0; i < propertiesResponse.getTokenCount(); i++) { if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING != propertiesResponse.tokenIs(i + 1)) cout << std::endl << "Host Properties: " << std::endl; else cout << " " << propertiesResponse.getString(i + 1) << " = " << propertiesResponse.getUint64(i + 2); i += 2; } if (!(i % 6)) cout << std::endl; } } } uint8_t DtaDevOpal::objDump(char *sp, char * auth, char *pass, char * objID) { LOG(D1) << "Entering DtaDevEnterprise::objDump"; LOG(D1) << sp << " " << auth << " " << pass << " " << objID; uint8_t lastRC; DtaCommand *get = new DtaCommand(); if (NULL == get) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } vector authority, object; uint8_t work; if (16 != strnlen(auth, 32)) { LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; return DTAERROR_INVALID_PARAMETER; } if (16 != strnlen(objID, 32)) { LOG(E) << "ObjectID must be 16 byte ascii string of hex object uid"; return DTAERROR_INVALID_PARAMETER; } authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = auth[i] & 0x40 ? 16 * ((auth[i] & 0xf) + 9) : 16 * (auth[i] & 0x0f); work += auth[i + 1] & 0x40 ? (auth[i + 1] & 0xf) + 9 : auth[i + 1] & 0x0f; authority.push_back(work); } object.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = objID[i] & 0x40 ? 16 * ((objID[i] & 0xf) + 9) : 16 * (objID[i] & 0x0f); work += objID[i + 1] & 0x40 ? (objID[i + 1] & 0xf) + 9 : objID[i + 1] & 0x0f; object.push_back(work); } get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GET); get->changeInvokingUid(object); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::STARTLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->addToken(OPAL_TOKEN::ENDLIST); get->complete(); LOG(I) << "Command:"; get->dumpCommand(); session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; delete get; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start((OPAL_UID)atoi(sp), pass, authority)) != 0) { delete get; delete session; return lastRC; } if ((lastRC = session->sendCommand(get, response)) != 0) { delete get; delete session; return lastRC; } LOG(I) << "Response:"; get->dumpResponse(); delete get; delete session; LOG(D1) << "Exiting DtaDevEnterprise::objDump"; return 0; } uint8_t DtaDevOpal::rawCmd(char *sp, char * hexauth, char *pass, char *hexinvokingUID, char *hexmethod, char *hexparms) { LOG(D1) << "Entering DtaDevEnterprise::rawCmd"; LOG(D1) << sp << " " << hexauth << " " << pass << " "; LOG(D1) << hexinvokingUID << " " << hexmethod << " " << hexparms; uint8_t lastRC; vector authority, object, invokingUID, method, parms; uint8_t work; if (16 != strnlen(hexauth, 32)) { LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; return DTAERROR_INVALID_PARAMETER; } authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexauth[i] & 0x40 ? 16 * ((hexauth[i] & 0xf) + 9) : 16 * (hexauth[i] & 0x0f); work += hexauth[i + 1] & 0x40 ? (hexauth[i + 1] & 0xf) + 9 : hexauth[i + 1] & 0x0f; authority.push_back(work); } if (16 != strnlen(hexinvokingUID, 32)) { LOG(E) << "invoker must be 16 byte ascii string of invoking uid"; return DTAERROR_INVALID_PARAMETER; } invokingUID.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexinvokingUID[i] & 0x40 ? 16 * ((hexinvokingUID[i] & 0xf) + 9) : 16 * (hexinvokingUID[i] & 0x0f); work += hexinvokingUID[i + 1] & 0x40 ? (hexinvokingUID[i + 1] & 0xf) + 9 : hexinvokingUID[i + 1] & 0x0f; invokingUID.push_back(work); } if (16 != strnlen(hexmethod, 32)) { LOG(E) << "invoker must be 16 byte ascii string of method uid"; return DTAERROR_INVALID_PARAMETER; } method.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (uint32_t i = 0; i < 16; i += 2) { work = hexmethod[i] & 0x40 ? 16 * ((hexmethod[i] & 0xf) + 9) : 16 * (hexmethod[i] & 0x0f); work += hexmethod[i + 1] & 0x40 ? (hexmethod[i + 1] & 0xf) + 9 : hexmethod[i + 1] & 0x0f; method.push_back(work); } if (1020 < strnlen(hexparms, 1024)) { LOG(E) << "Parmlist limited to 1020 characters"; return DTAERROR_INVALID_PARAMETER; } if (strnlen(hexparms, 1024) % 2) { LOG(E) << "Parmlist must be even number of bytes"; return DTAERROR_INVALID_PARAMETER; } for (uint32_t i = 0; i < strnlen(hexparms, 1024); i += 2) { work = hexparms[i] & 0x40 ? 16 * ((hexparms[i] & 0xf) + 9) : 16 * (hexparms[i] & 0x0f); work += hexparms[i + 1] & 0x40 ? (hexparms[i + 1] & 0xf) + 9 : hexparms[i + 1] & 0x0f; parms.push_back(work); } DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; return DTAERROR_OBJECT_CREATE_FAILED; } cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, method); cmd->changeInvokingUid(invokingUID); cmd->addToken(parms); cmd->complete(); session = new DtaSession(this); if (NULL == session) { LOG(E) << "Unable to create session object "; delete cmd; return DTAERROR_OBJECT_CREATE_FAILED; } if ((lastRC = session->start((OPAL_UID)atoi(sp), pass, authority)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "Command:"; cmd->dumpCommand(); if ((lastRC = session->sendCommand(cmd, response)) != 0) { delete cmd; delete session; return lastRC; } LOG(I) << "Response:"; cmd->dumpResponse(); delete cmd; delete session; LOG(D1) << "Exiting DtaDevEnterprise::rawCmd"; return 0; }sedutil-1.20.0/Common/DtaDevOpal.h000066400000000000000000000330411410717517300166360ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once class DtaCommand; class DtaSession; #include "DtaDev.h" #include "DtaDevOS.h" #include "DtaStructures.h" #include "DtaLexicon.h" #include "DtaResponse.h" // wouldn't take class #include using namespace std; /** Common code for OPAL SSCs. * most of the code that works for OPAL 2.0 also works for OPAL 1.0 * that common code is implemented in this class */ class DtaDevOpal : public DtaDevOS { public: /** Default Constructor */ DtaDevOpal(); /** default Destructor */ ~DtaDevOpal(); /** OS specific initialization. * This function should perform the necessary authority and environment checking * to allow proper functioning of the program, open the device, perform an ATA * identify, add the fields from the identify response to the disk info structure * and if the device is an ATA device perform a call to Discovery0() to complete * the disk_info structure * @param devref character representation of the device is standard OS lexicon */ void init(const char * devref); /** Notify the device of the host properties and receive the * properties of the device as a reply */ uint8_t properties(); /** Send a command to the device and wait for the response * @param cmd the MswdCommand object containg the command * @param response the DtaResonse object containing the response * @param protocol The security protocol number to use for the command */ uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01); /** return the communications ID to be used for sessions to this device */ virtual uint16_t comID() = 0; /** Change the SID password from it's MSID default * @param newpassword new password for SID */ uint8_t takeOwnership(char * newpassword); /** retrieve the MSID password */ uint8_t printDefaultPassword(); /** retrieve a single row from a table * @param table the UID of the table * @param startcol the starting column of data requested * @param endcol the ending column of the data requested */ uint8_t getTable(vector table, uint16_t startcol, uint16_t endcol); /** Set the SID password. * Requires special handling because password is not always hashed. * @param oldpassword current SID password * @param newpassword value password is to be changed to * @param hasholdpwd is the old password to be hashed before being added to the bytestream * @param hashnewpwd is the new password to be hashed before being added to the bytestream */ uint8_t setSIDPassword(char * oldpassword, char * newpassword, uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1); /** set a single column in an object table * @param table the UID of the table * @param name the column name to be set * @param value data to be stored the the column */ uint8_t setTable(vector table, OPAL_TOKEN name, vector value); /** set a single column in an object table * @param table the UID of the table * @param name the column name to be set * @param value data to be stored the the column */ uint8_t setTable(vector table, OPAL_TOKEN name, OPAL_TOKEN value); /** Change state of the Locking SP to active. * Enables locking * @param password current SID password */ uint8_t activateLockingSP(char * password); /** Change state of the Locking SP to active in Single User Mode. * Enables locking in Single User Mode * @param lockingrange the locking range number to activate in SUM * @param password current SID password */ uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); /** Erase a Single User Mode locking range by calling the drive's erase method * @param lockingrange The Locking Range to erase * @param password The administrator password for the drive */ uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); /** Restore the state of the Locking SP to factory defaults. * Enables locking * @param password current SID password * @param keep boolean keep the data (NOT FUNCTIONAL) */ uint8_t revertLockingSP(char * password, uint8_t keep = 0); /** get the UID or CPIN ID of a user from their character name * @param userid Character user name * @param column UID or CPIN to be returned * @param userData The UIS or CPIN of the USER */ uint8_t getAuth4User(char * userid, uint8_t column, std::vector &userData); /** Enable a user in the Locking SP * @param password the password of the Locking SP administrative authority * @param userid Character name of the user to be enabled */ uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE); /** Primitive to set the MBRDone flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag * @param status true or false to enable/disable */ uint8_t setMBRDone(uint8_t state, char * Admin1Password); /** Primitive to set the MBREnable flag. * @param state 0 or 1 * @param Admin1Password Locking SP authority with access to flag */ uint8_t setMBREnable(uint8_t state, char * Admin1Password); /** Set the password of a locking SP user. * @param password current password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ uint8_t setPassword(char * password, char * userid, char * newpassword); /** Set the password of a locking SP user in Single User Mode. * @param password current user password * @param userid the userid whose password is to be changed * @param newpassword value password is to be changed to */ uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword); /** User command to manipulate the state of a locking range. * RW|RO|LK are the supported states @see OPAL_LOCKINGSTATE * @param lockingrange locking range number * @param lockingstate desired locking state (see above) * @param Admin1Password password of the locking administrative authority */ uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, char * Admin1Password); /** Change the locking state of a locking range in Single User Mode * @param lockingrange The number of the locking range (0 = global) * @param lockingstate the locking state to set * @param password password of user authority for the locking range */ uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, char * password); /** Setup a locking range. Initialize a locking range, set it's start * LBA and length, initialize it as unlocked with locking disabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @param password Password of administrator */ uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** Setup a locking range in Single User Mode. Initialize a locking range, * set it's start LBA and length, initialize it as unlocked with locking enabled. * @paran lockingrange The Locking Range to be setup * @param start Starting LBA * @param length Number of blocks * @paran password Password of administrator */ uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char * password); /** List status of locking ranges. * @param password Password of administrator */ uint8_t listLockingRanges(char * password, int16_t rangeid); /** User command to enable/disable a locking range. * RW|RO|LK are the supported states @see OPAL_LOCKINGSTATE * @param lockingrange locking range number * @param enabled boolean true = enabled, false = disabled * @param password password of the locking administrative authority */ uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password); /** Generate a new encryption key for a locking range. * @param lockingrange locking range number * @param password password of the locking administrative authority */ uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); /** Generate a new encryption key for a Single User Mode locking range. * @param LR locking range UID in vector format * @param UID user UID in vector format * @param password password of the UID authority */ uint8_t rekeyLockingRange_SUM(vector LR, vector UID, char * password); /** Reset the TPER to its factory condition * ERASES ALL DATA! * @param password password of authority (SID or PSID) * @param PSID true or false is the authority the PSID * */ /** Enable bands using MSID. * @param lockingrange locking range number */ uint8_t setBandsEnabled(int16_t rangeid, char * password); uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0); /** Erase a locking range * @param lockingrange The number of the locking range (0 = global) * @param password Password of administrative authority for locking range */ uint8_t eraseLockingRange(uint8_t lockingrange, char * password); /** Loads a disk image file to the shadow MBR table. * @param password the password for the administrative authority with access to the table * @param filename the filename of the disk image */ uint8_t loadPBA(char * password, char * filename); /** User command to prepare the device for management by sedutil. * Specific to the SSC that the device supports * @param password the password that is to be assigned to the SSC master entities */ uint8_t initialSetup(char * password); /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. * @param lockingrange locking range number to enable * @param start LBA to start locking range * @param length length (in blocks) for locking range * @param Admin1Password admin1 password for TPer * @param password User password to set for locking range */ uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); /** Displays the identify and discovery 0 information */ void puke(); /** Dumps an object for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param objID the UID of the object to dump * */ uint8_t objDump(char *sp, char * auth, char *pass, char * objID); /** Issue any command to the drive for diagnostic purposes * @param sp index into the OPALUID table for the SP the object is in * @param auth the authority ti use for the dump * @param pass the password for the suthority * @param invoker caller of the method * @param method the method to call * @param plist the parameter list for the command * */ uint8_t rawCmd(char *sp, char * auth, char *pass, char *invoker, char *method, char *plist); protected: /** Primitive to handle the setting of a value in the locking sp. * @param table_uid UID of the table * @param name column to be altered * @param value the value to be set * @param password password for the administrative authority * @param msg message to be displayed upon successful update; */ uint8_t setLockingSPvalue(OPAL_UID table_uid, OPAL_TOKEN name, OPAL_TOKEN value, char * password, char * msg = (char *) "New Value Set"); uint8_t getDefaultPassword(); typedef struct lrStatus { uint8_t command_status; //return code of locking range query command uint8_t lockingrange_num; //which locking range is this uint64_t start; uint64_t size; bool RLKEna; bool WLKEna; bool RLocked; bool WLocked; }lrStatus_t; /** Get info programatically for single locking range * @param lockingrange locking range number to check * @param password Admin1 Password for TPer */ lrStatus_t getLockingRange_status(uint8_t lockingrange, char * password); }; sedutil-1.20.0/Common/DtaDevOpal1.cpp000066400000000000000000000021441410717517300172520ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "DtaDevOpal1.h" using namespace std; DtaDevOpal1::DtaDevOpal1 (const char * devref) { DtaDevOpal::init(devref); assert(isOpal1()); } DtaDevOpal1::~DtaDevOpal1() { } uint16_t DtaDevOpal1::comID() { return disk_info.OPAL10_basecomID; } sedutil-1.20.0/Common/DtaDevOpal1.h000066400000000000000000000025351410717517300167230ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include "os.h" #include "DtaDevOpal.h" using namespace std; /** Class representing a disk device, this class is represents a disk that conforms * to the OPAL 1.0 SSC * * testing so far indicates that the functions implemented in this program * operate the same in OPAL 1.0 and Opal 2.0 */ class DtaDevOpal1 : public DtaDevOpal { public: DtaDevOpal1(const char * devref); ~DtaDevOpal1(); /** return the communication ID to be used with this device */ uint16_t comID(); };sedutil-1.20.0/Common/DtaDevOpal2.cpp000066400000000000000000000021441410717517300172530ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "DtaDevOpal2.h" using namespace std; DtaDevOpal2::DtaDevOpal2 (const char * devref) { DtaDevOpal::init(devref); assert(isOpal2()); } DtaDevOpal2::~DtaDevOpal2() { } uint16_t DtaDevOpal2::comID() { return disk_info.OPAL20_basecomID; } sedutil-1.20.0/Common/DtaDevOpal2.h000066400000000000000000000025351410717517300167240ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include "os.h" #include "DtaDevOpal.h" using namespace std; /** Class representing a disk device, this class is represents a disk that conforms * to the OPAL 2.0 SSC * * testing so far indicates that the functions implemented in this program * function the same in OPAL 1.0 and Opal 2.0 */ class DtaDevOpal2 : public DtaDevOpal { public: DtaDevOpal2(const char * devref); ~DtaDevOpal2(); /** return the communication ID to be used with this device */ uint16_t comID(); };sedutil-1.20.0/Common/DtaDiskType.cpp000066400000000000000000000024671410717517300174030ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "DtaDiskType.h" using namespace std; DtaDiskType::DtaDiskType() {} DtaDiskType::~DtaDiskType() {} #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4100) #endif void DtaDiskType::init(const char * devref) {} uint8_t DtaDiskType::sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, void * buffer, uint32_t bufferlen) { return 10; } void DtaDiskType::identify(OPAL_DiskInfo& disk_info) {} #ifdef _MSC_VER #pragma warning(pop) #endif sedutil-1.20.0/Common/DtaDiskType.h000066400000000000000000000042041410717517300170370ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include "os.h" #include "DtaStructures.h" /** Device specific implementation of disk access functions. */ class DtaDiskType { public: DtaDiskType(); virtual ~DtaDiskType(); /** device specific initialization. * This function should perform the necessary authority and environment checking * to allow proper functioning of the program, open the device, perform an * identify, add the fields from the identify response to the disk info structure * and if the device is an ATA device perform a call to Discovery0() to complete * the disk_info structure * @param devref character representation of the device is standard OS lexicon */ virtual void init(const char * devref); /** OS specific method to send an ATA command to the device * @param cmd command to be sent to the device * @param protocol security protocol to be used in the command * @param comID communications ID to be used * @param buffer input/output buffer * @param bufferlen length of the input/output buffer */ virtual uint8_t sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, void * buffer, uint32_t bufferlen); /** OS specific routine to send an ATA identify to the device * @param disk_info structure to fill in with drive information */ virtual void identify(OPAL_DiskInfo& disk_info); }; sedutil-1.20.0/Common/DtaEndianFixup.h000066400000000000000000000037561410717517300175300ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ /* These are a few macros to fixup the endianess of the data * returned by the drive as specified in the TCG OPAL SSC standards * Since this is a low use utility program it shouldn't be to * ugly that these are macros */ /* * Windows provides system call in the network stack to do this but * I've never had much luck when the winsock headers get in the mix */ // //TODO: add a test on the endianess of the system and define // empty macros if the system is big endian #pragma once #ifdef __gnu_linux__ #include #if __BYTE_ORDER != __LITTLE_ENDIAN #error This code does not support big endian architectures #endif #endif /** change the "endianess" of a 16bit field */ #define SWAP16(x) ((uint16_t) ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8)) /** change the "endianess" of a 32bit field */ #define SWAP32(x) ((uint32_t) (((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8) \ | (((x) & 0x00ff0000) >> 8) | (((x) & 0xff000000) >> 24)) /** change the "endianess" of a 64bit field */ #define SWAP64(x) (uint64_t) \ ((uint64_t) (SWAP32((x & 0x00000000ffffffff)) << 32) | \ ((uint64_t) (SWAP32((x >> 32))) ) \ ) sedutil-1.20.0/Common/DtaHashPwd.cpp000066400000000000000000000140601410717517300171750ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include #include "DtaHashPwd.h" #include "DtaLexicon.h" #include "DtaOptions.h" #include "DtaDev.h" #include "log.h" extern "C" { #include "pbkdf2.h" #include "sha1.h" } using namespace std; void DtaHashPassword(vector &hash, char * password, vector salt, unsigned int iter, uint8_t hashsize) { LOG(D1) << " Entered DtaHashPassword"; // if the hashsize can be > 255 the token overhead logic needs to be fixed assert(1 == sizeof(hashsize)); if (253 < hashsize) { LOG(E) << "Hashsize > 253 incorrect token generated"; } hash.clear(); // don't hash the devault OPAL password '' if (0 == strnlen(password, 32)) { goto exit; } hash.reserve(hashsize + 2); // hope this will prevent reallocation for (uint16_t i = 0; i < hashsize; i++) { hash.push_back(' '); } cf_pbkdf2_hmac((uint8_t *)password, strnlen(password, 256), salt.data(), salt.size(), iter, hash.data(), hash.size(), &cf_sha1); // gc_pbkdf2_sha1(password, strnlen(password, 256), (const char *)salt.data(), salt.size(), iter, // (char *)hash.data(), hash.size()); exit: // add the token overhead hash.insert(hash.begin(), (uint8_t)hash.size()); hash.insert(hash.begin(), 0xd0); } void DtaHashPwd(vector &hash, char * password, DtaDev * d) { LOG(D1) << " Entered DtaHashPwd"; char *serNum; if (d->no_hash_passwords) { hash.clear(); for (uint16_t i = 0; i < strnlen(password, 32); i++) hash.push_back(password[i]); // add the token overhead hash.insert(hash.begin(), (uint8_t)hash.size()); hash.insert(hash.begin(), 0xd0); LOG(D1) << " Exit DtaHashPwd"; return; } serNum = d->getSerialNum(); vector salt(serNum, serNum + 20); // vector salt(DEFAULTSALT); DtaHashPassword(hash, password, salt); LOG(D1) << " Exit DtaHashPwd"; // log for hash timing } struct PBKDF_TestTuple { uint8_t hashlen; unsigned int iterations; const char *Password, *Salt, *hexDerivedKey; }; int testresult(std::vector &result, const char * expected, size_t len) { char work[50]; if (len > 50) return 1; int p = 0; printf("Expected Result: %s\nActual Result : ", expected); for (uint32_t i = 0; i < len; i++) { printf("%02x", result[i + 2]); }; printf("\n"); for (uint32_t i = 0; i < len * 2; i += 2) { work[p] = expected[i] & 0x40 ? 16 * ((expected[i] & 0xf) + 9) : 16 * (expected[i] & 0xf); work[p] += expected[i + 1] & 0x40 ? (expected[i + 1] & 0xf) + 9 : expected[i + 1] & 0xf; p++; } return memcmp(result.data()+2, work, len); } int Testsedutil(const PBKDF_TestTuple *testSet, unsigned int testSetSize) { int pass = 1; std::vector hash, seaSalt; for (unsigned int i = 0; i < testSetSize; i++) { const PBKDF_TestTuple &tuple = testSet[i]; hash.clear(); seaSalt.clear(); for (uint16_t j = 0; j < strnlen(tuple.Salt, 255); j++) { seaSalt.push_back(tuple.Salt[j]); } printf("Password %s Salt %s Iterations %i Length %i\n", (char *)tuple.Password, (char *) tuple.Salt, tuple.iterations, tuple.hashlen); DtaHashPassword(hash, (char *) tuple.Password, seaSalt, tuple.iterations, tuple.hashlen); int fail = (testresult(hash, tuple.hexDerivedKey, tuple.hashlen) == 0); pass = pass & fail; } return pass; } int TestPBKDF2() { int pass = 1; // from draft-ietf-smime-password-03.txt, at http://www.imc.org/draft-ietf-smime-password PBKDF_TestTuple testSet[] = { // Draft PKCS #5 PBKDF2 Test Vectors http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 // "password" (8 octets) S = "salt" (4 octets) c = 1 DK = 0c60c80f961f0e71f3a9b524af6012062fe037a6 { 20, 1, "password", "salt", "0c60c80f961f0e71f3a9b524af6012062fe037a6"}, // "password" (8 octets) S = "salt" (4 octets) c = 2 DK = ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957 { 20, 2, "password", "salt", "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"}, // "password" (8 octets) S = "salt" (4 octets) c = 4096 DK = 4b007901b765489abead49d926f721d065a429c1 { 20, 4096, "password", "salt", "4b007901b765489abead49d926f721d065a429c1"}, // "password" (8 octets) S = "salt" (4 octets) c = 16777216 DK = eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 //{ 20, 16777216, "password", "salt", "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984" }, // "passwordPASSWORDpassword" (24 octets) S = "saltSALTsaltSALTsaltSALTsaltSALTsalt" (36 octets) c = 4096 DK = 3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038 { 25, 4096, "passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"}, // "pass\0word" (9 octets) S = "sa\0lt" (5 octets) c = 4096 DK = 56fa6aa75548099dcc37d7f03425e0c3 //{ 16, 4096, "pass\0word", "sa\0lt", "56fa6aa75548099dcc37d7f03425e0c3" }, // program receives char * from OS so this test would fail but is not possible IRL }; cout << "\nPKCS #5 PBKDF2 validation suite running ... \n\n"; pass = Testsedutil(testSet, sizeof (testSet) / sizeof (testSet[0])) && pass; cout << "\nPKCS #5 PBKDF2 validation suite ... "; if (pass) cout << "passed\n"; else cout << "**FAILED**\n"; return 0; } sedutil-1.20.0/Common/DtaHashPwd.h000066400000000000000000000037441410717517300166510ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include class DtaDev; using namespace std; /** Hash the password using the drive serial number as salt. * This is far from ideal but it's better that a single salt as * it should prevent attacking the password with a prebuilt table * * This is an intermediary pass through so that the real hash * function (DtaHashPassword) can be tested and verified. * @param hash The field whare the hash is to be placed * @param password The password to be hashed * @param device the device where the password is to be used */ void DtaHashPwd(vector &hash, char * password, DtaDev * device); /** Hash a passwor using the PBDKF2 function * * @param hash Field where hash returned * @param password password to be hashed * @param salt salt to be used in the hash * @param iter number of iterations to be preformed * @param hashsize size of hash to be returned */ void DtaHashPassword(vector &hash, char * password, vector salt, unsigned int iter = 75000, uint8_t hashsize = 32); /** Test the hshing function using publicly available test cased and report */ int TestPBKDF2(); sedutil-1.20.0/Common/DtaHexDump.cpp000066400000000000000000000033621410717517300172140ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include void DtaHexDump(void * address, int length) { uint8_t display[17]; uint8_t * cpos = (uint8_t *)address; uint8_t * epos = cpos + length; LOG(D1) << "Entering hexDump"; int rpos = 0; int dpos = 0; fprintf( stderr,"%04x ",rpos); while (cpos < epos){ fprintf( stderr,"%02x", cpos[0]); if (!((++rpos) % 4))fprintf( stderr," "); display[dpos++] = (isprint(cpos[0]) ? cpos[0] : 0x2e ); cpos += 1; if (16 == dpos) { dpos = 0; display[16] = 0x00; fprintf( stderr," %s \n", display); if(cpos < epos) fprintf( stderr,"%04x ", rpos); memset(&display,0,sizeof(display)); } } if (dpos != 0) { if (dpos % 4) fprintf( stderr," "); fprintf( stderr," "); for (int i = dpos ; i < 15; i++) { if (!(i % 4)) fprintf( stderr," "); fprintf( stderr," "); } display[dpos] = 0x00; fprintf( stderr," %s\n", display); } }sedutil-1.20.0/Common/DtaHexDump.h000066400000000000000000000020641410717517300166570ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once /** Print a hexdump of an area of memory * @param address Starting address for the dump * @param length Length of the area to be dumped */ void DtaHexDump(void * address, int length);sedutil-1.20.0/Common/DtaLexicon.h000066400000000000000000000216321410717517300167100ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once /* * Define the structures and enums needed to map the * Opal SSC Pseudo code to procedures. * * no effort has been made to be complete, these are the values * that are required for the basic functionality provided in this * program. */ /** User IDs used in the TCG storage SSCs */ static const uint8_t OPALUID[][8]{ // users { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /**< session management */ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, /**< special "thisSP" syntax */ { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, /**< Administrative SP */ { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, /**< Locking SP */ { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, /**< ENTERPRISE Locking SP */ { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, /** This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include "DtaOptions.h" #include "DtaLexicon.h" #include "Version.h" void usage() { printf("sedutil v%s Copyright 2014-2017 Bright Plaza Inc. \n", GIT_VERSION); printf("a utility to manage self encrypting drives that conform\n"); printf("to the Trusted Computing Group OPAL 2.0 SSC specification\n"); printf("General Usage: (see readme for extended commandset)\n"); printf("sedutil-cli <-v> <-n> \n"); printf("-v (optional) increase verbosity, one to five v's\n"); printf("-n (optional) no password hashing. Passwords will be sent in clear text!\n"); printf("-l (optional) log style output to stderr only\n"); printf("actions \n"); printf("--scan \n"); printf(" Scans the devices on the system \n"); printf(" identifying Opal compliant devices \n"); printf("--query \n"); printf(" Display the Discovery 0 response of a device\n"); printf("--isValidSED \n"); printf(" Verify whether the given device is SED or not\n"); printf("--listLockingRanges \n"); printf(" List all Locking Ranges\n"); printf("--listLockingRange <0...n> \n"); printf(" List all Locking Ranges\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--rekeyLockingRange <0...n> \n"); printf(" 0 = GLobal 1..n = LRn \n"); printf(" Rekey Locking Range\n"); printf("--setBandsEnabled \n"); printf(" Set Enabled for all Locking Ranges\n"); printf(" (passwort = \"\" for MSID) \n"); printf("--setBandEnabled <0...n> \n"); printf(" Set Enabled for Locking Range[n]\n"); printf(" (passwort = \"\" for MSID) \n"); printf("--eraseLockingRange <0...n> \n"); printf(" Erase a Locking Range\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--setupLockingRange <0...n> \n"); printf(" Setup a new Locking Range\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--initialSetup \n"); printf(" Setup the device for use with sedutil\n"); printf(" is new SID and Admin1 password\n"); printf("--setSIDPassword \n"); printf(" Change the SID password\n"); printf("--setAdmin1Pwd \n"); printf(" Change the Admin1 password\n"); printf("--setPassword \n"); printf(" Change the Enterprise password for userid\n"); printf(" \"EraseMaster\" or \"BandMaster\", 0 <= n <= 1023\n"); printf("--setLockingRange <0...n> \n"); printf(" Set the status of a Locking Range\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--enableLockingRange <0...n> \n"); printf(" Enable a Locking Range\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--disableLockingRange <0...n> \n"); printf(" Disable a Locking Range\n"); printf(" 0 = GLobal 1..n = LRn \n"); printf("--setMBREnable \n"); printf(" Enable|Disable MBR shadowing \n"); printf("--setMBRDone \n"); printf(" set|unset MBRDone\n"); printf("--loadPBAimage \n"); printf(" Write to MBR Shadow area\n"); printf("--revertTPer \n"); printf(" set the device back to factory defaults \n"); printf(" This **ERASES ALL DATA** \n"); printf("--revertNoErase \n"); printf(" deactivate the Locking SP \n"); printf(" without erasing the data \n"); printf(" on GLOBAL RANGE *ONLY* \n"); printf("--yesIreallywanttoERASEALLmydatausingthePSID \n"); printf(" revert the device using the PSID *ERASING* *ALL* the data \n"); printf("--printDefaultPassword \n"); printf(" print MSID \n"); printf("\n"); printf("Examples \n"); printf("sedutil-cli --scan \n"); printf("sedutil-cli --query %s \n", DEVICEEXAMPLE); printf("sedutil-cli --yesIreallywanttoERASEALLmydatausingthePSID %s \n", DEVICEEXAMPLE); printf("sedutil-cli --initialSetup %s \n", DEVICEEXAMPLE); return; } uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts) { memset(opts, 0, sizeof (DTA_OPTIONS)); uint16_t loggingLevel = 2; uint8_t baseOptions = 2; // program and option CLog::Level() = CLog::FromInt(loggingLevel); RCLog::Level() = RCLog::FromInt(loggingLevel); if (2 > argc) { usage(); return DTAERROR_INVALID_COMMAND; } for (uint8_t i = 1; i < argc; i++) { if (!(strcmp("-h", argv[i])) || !(strcmp("--help", argv[i]))) { usage(); return DTAERROR_INVALID_COMMAND; } else if ('v' == argv[i][1]) { baseOptions += 1; loggingLevel += (uint16_t)(strlen(argv[i]) - 1); if (loggingLevel > 7) loggingLevel = 7; CLog::Level() = CLog::FromInt(loggingLevel); RCLog::Level() = RCLog::FromInt(loggingLevel); LOG(D) << "Log level set to " << CLog::ToString(CLog::FromInt(loggingLevel)); LOG(D) << "sedutil version : " << GIT_VERSION; } else if (!(strcmp("-n", argv[i]))) { baseOptions += 1; opts->no_hash_passwords = true; LOG(D) << "Password hashing is disabled"; } else if (!strcmp("-l", argv[i])) { baseOptions += 1; opts->output_format = sedutilNormal; outputFormat = sedutilNormal; } else if (!(('-' == argv[i][0]) && ('-' == argv[i][1])) && (0 == opts->action)) { LOG(E) << "Argument " << (uint16_t) i << " (" << argv[i] << ") should be a command"; return DTAERROR_INVALID_COMMAND; } BEGIN_OPTION(initialSetup, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setSIDPassword, 3) OPTION_IS(password) OPTION_IS(newpassword) OPTION_IS(device) END_OPTION BEGIN_OPTION(setup_SUM, 6) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(lrstart) OPTION_IS(lrlength) OPTION_IS(password) OPTION_IS(newpassword) OPTION_IS(device) END_OPTION BEGIN_OPTION(setAdmin1Pwd, 3) OPTION_IS(password) OPTION_IS(newpassword) OPTION_IS(device) END_OPTION BEGIN_OPTION(loadPBAimage, 3) OPTION_IS(password) OPTION_IS(pbafile) OPTION_IS(device) END_OPTION BEGIN_OPTION(revertTPer, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(revertNoErase, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(PSIDrevert, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(PSIDrevertAdminSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(yesIreallywanttoERASEALLmydatausingthePSID, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(enableuser, 2) OPTION_IS(password) OPTION_IS(userid) OPTION_IS(device) END_OPTION BEGIN_OPTION(activateLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(activateLockingSP_SUM, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(eraseLockingRange_SUM, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (1-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(query, 1) OPTION_IS(device) END_OPTION BEGIN_OPTION(scan, 0) END_OPTION BEGIN_OPTION(isValidSED, 1) OPTION_IS(device) END_OPTION BEGIN_OPTION(eraseLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(takeOwnership, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(revertLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setPassword, 4) OPTION_IS(password) OPTION_IS(userid) OPTION_IS(newpassword) OPTION_IS(device) END_OPTION BEGIN_OPTION(setPassword_SUM, 4) OPTION_IS(password) OPTION_IS(userid) OPTION_IS(newpassword) OPTION_IS(device) END_OPTION BEGIN_OPTION(validatePBKDF2, 0) END_OPTION BEGIN_OPTION(setMBREnable, 3) TESTARG(ON, mbrstate, 1) TESTARG(on, mbrstate, 1) TESTARG(off, mbrstate, 0) TESTARG(OFF, mbrstate, 0) TESTFAIL("Invalid setMBREnable argument not ") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setMBRDone, 3) TESTARG(ON, mbrstate, 1) TESTARG(on, mbrstate, 1) TESTARG(off, mbrstate, 0) TESTARG(OFF, mbrstate, 0) TESTFAIL("Invalid setMBRDone argument not ") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setLockingRange, 4) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") TESTARG(RW, lockingstate, OPAL_LOCKINGSTATE::READWRITE) TESTARG(rw, lockingstate, OPAL_LOCKINGSTATE::READWRITE) TESTARG(RO, lockingstate, OPAL_LOCKINGSTATE::READONLY) TESTARG(ro, lockingstate, OPAL_LOCKINGSTATE::READONLY) TESTARG(LK, lockingstate, OPAL_LOCKINGSTATE::LOCKED) TESTARG(lk, lockingstate, OPAL_LOCKINGSTATE::LOCKED) TESTFAIL("Invalid locking state ") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setLockingRange_SUM, 4) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") TESTARG(RW, lockingstate, OPAL_LOCKINGSTATE::READWRITE) TESTARG(rw, lockingstate, OPAL_LOCKINGSTATE::READWRITE) TESTARG(RO, lockingstate, OPAL_LOCKINGSTATE::READONLY) TESTARG(ro, lockingstate, OPAL_LOCKINGSTATE::READONLY) TESTARG(LK, lockingstate, OPAL_LOCKINGSTATE::LOCKED) TESTARG(lk, lockingstate, OPAL_LOCKINGSTATE::LOCKED) TESTFAIL("Invalid locking state ") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(enableLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(disableLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setupLockingRange, 5) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(lrstart) OPTION_IS(lrlength) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setupLockingRange_SUM, 5) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(lrstart) OPTION_IS(lrlength) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(readonlyLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(listLockingRanges, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(listLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(rekeyLockingRange, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setBandsEnabled, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(setBandEnabled, 3) TESTARG(0, lockingrange, 0) TESTARG(1, lockingrange, 1) TESTARG(2, lockingrange, 2) TESTARG(3, lockingrange, 3) TESTARG(4, lockingrange, 4) TESTARG(5, lockingrange, 5) TESTARG(6, lockingrange, 6) TESTARG(7, lockingrange, 7) TESTARG(8, lockingrange, 8) TESTARG(9, lockingrange, 9) TESTARG(10, lockingrange, 10) TESTARG(11, lockingrange, 11) TESTARG(12, lockingrange, 12) TESTARG(13, lockingrange, 13) TESTARG(14, lockingrange, 14) TESTARG(15, lockingrange, 15) TESTFAIL("Invalid Locking Range (0-15)") OPTION_IS(password) OPTION_IS(device) END_OPTION BEGIN_OPTION(objDump, 5) i += 4; OPTION_IS(device) END_OPTION BEGIN_OPTION(printDefaultPassword, 1) OPTION_IS(device) END_OPTION BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION else { LOG(E) << "Invalid command line argument " << argv[i]; return DTAERROR_INVALID_COMMAND; } } return 0; } sedutil-1.20.0/Common/DtaOptions.h000066400000000000000000000076731410717517300167530ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #ifndef _DTAOPTIONS_H #define _DTAOPTIONS_H /** Output modes */ typedef enum _sedutiloutput { sedutilNormal, sedutilReadable, sedutilJSON } sedutiloutput; /** Structure representing the command line issued to the program */ typedef struct _DTA_OPTIONS { uint8_t password; /**< password supplied */ uint8_t userid; /**< userid supplied */ uint8_t newpassword; /**< new password for password change */ uint8_t pbafile; /**< file name for loadPBAimage command */ uint8_t device; /**< device name */ uint8_t action; /**< option requested */ uint8_t mbrstate; /**< mbrstate for set mbr commands */ uint8_t lockingrange; /**< locking range to be manipulated */ uint8_t lockingstate; /**< locking state to set a lockingrange to */ uint8_t lrstart; /** the starting block of a lockingrange */ uint8_t lrlength; /** the length in blocks of a lockingrange */ bool no_hash_passwords; /** global parameter, disables hashing of passwords */ sedutiloutput output_format; } DTA_OPTIONS; /** Print a usage message */ void usage(); /** Parse the command line and return a structure that describes the action desired * @param argc program argc parameter * @param argv program argv paramater * @param opts pointer to options structure to be filled out */ uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts); /** Command line options implemented in sedutil */ typedef enum _sedutiloption { deadbeef, // 0 should indicate no action specified initialSetup, setSIDPassword, setup_SUM, setAdmin1Pwd, setPassword, setPassword_SUM, loadPBAimage, setLockingRange, revertTPer, revertNoErase, setLockingRange_SUM, revertLockingSP, PSIDrevert, PSIDrevertAdminSP, yesIreallywanttoERASEALLmydatausingthePSID, enableLockingRange, disableLockingRange, readonlyLockingRange, setupLockingRange, setupLockingRange_SUM, listLockingRanges, listLockingRange, rekeyLockingRange, setBandsEnabled, setBandEnabled, setMBREnable, setMBRDone, enableuser, activateLockingSP, activateLockingSP_SUM, eraseLockingRange_SUM, query, scan, isValidSED, eraseLockingRange, takeOwnership, validatePBKDF2, objDump, printDefaultPassword, rawCmd, } sedutiloption; /** verify the number of arguments passed */ #define CHECKARGS(x) \ if((x+baseOptions) != argc) { \ LOG(E) << "Incorrect number of paramaters for " << argv[i] << " command"; \ return 100; \ } /** Test the command input for a recognized argument */ #define BEGIN_OPTION(cmdstring,args) \ else if (!(strcasecmp(#cmdstring, &argv[i][2]))) { \ CHECKARGS(args) \ opts->action = sedutiloption::cmdstring; \ /** end of an OPTION */ #define END_OPTION } /** test an argument for a value */ #define TESTARG(literal,structfield,value) \ if (!(strcasecmp(#literal, argv[i + 1]))) \ {opts->structfield = value;} else /** if all testargs fail then do this */ #define TESTFAIL(msg) \ { \ LOG(E) << msg << " " << argv[i+1]; \ return 1;\ } \ i++; /** set the argc value for this parameter in the options structure */ #define OPTION_IS(option_field) \ opts->option_field = ++i; #endif /* _DTAOPTIONS_H */ sedutil-1.20.0/Common/DtaResponse.cpp000066400000000000000000000173211410717517300174400ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include "DtaResponse.h" #include "DtaEndianFixup.h" using namespace std; DtaResponse::DtaResponse() { LOG(D1) << "Creating DtaResponse()"; } DtaResponse::DtaResponse(void * buffer) { LOG(D1) << "Creating DtaResponse(buffer)"; init(buffer); } void DtaResponse::init(void * buffer) { LOG(D1) << "Entering DtaResponse::init"; std::vector bytestring, empty_atom(1, 0xff); uint8_t * reply = (uint8_t *) buffer; uint32_t cpos = 0; uint32_t tokenLength; memcpy(&h, buffer, sizeof (OPALHeader)); response.clear(); reply += sizeof (OPALHeader); while (cpos < SWAP32(h.subpkt.length)) { bytestring.clear(); if (!(reply[cpos] & 0x80)) //tiny atom tokenLength = 1; else if (!(reply[cpos] & 0x40)) // short atom tokenLength = (reply[cpos] & 0x0f) + 1; else if (!(reply[cpos] & 0x20)) // medium atom tokenLength = (((reply[cpos] & 0x07) << 8) | reply[cpos + 1]) + 2; else if (!(reply[cpos] & 0x10)) // long atom tokenLength = ((reply[cpos + 1] << 16) | (reply[cpos + 2] << 8) | reply[cpos + 3]) + 4; else // TOKEN tokenLength = 1; for (uint32_t i = 0; i < tokenLength; i++) { bytestring.push_back(reply[cpos++]); } if (bytestring != empty_atom) response.push_back(bytestring); } } OPAL_TOKEN DtaResponse::tokenIs(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::tokenIs"; if (!(response[tokenNum][0] & 0x80)) { //tiny atom if ((response[tokenNum][0] & 0x40)) return OPAL_TOKEN::DTA_TOKENID_SINT; else return OPAL_TOKEN::DTA_TOKENID_UINT; } else if (!(response[tokenNum][0] & 0x40)) { // short atom if ((response[tokenNum][0] & 0x20)) return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; else if ((response[tokenNum][0] & 0x10)) return OPAL_TOKEN::DTA_TOKENID_SINT; else return OPAL_TOKEN::DTA_TOKENID_UINT; } else if (!(response[tokenNum][0] & 0x20)) { // medium atom if ((response[tokenNum][0] & 0x10)) return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; else if ((response[tokenNum][0] & 0x08)) return OPAL_TOKEN::DTA_TOKENID_SINT; else return OPAL_TOKEN::DTA_TOKENID_UINT; } else if (!(response[tokenNum][0] & 0x10)) { // long atom if ((response[tokenNum][0] & 0x02)) return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; else if ((response[tokenNum][0] & 0x01)) return OPAL_TOKEN::DTA_TOKENID_SINT; else return OPAL_TOKEN::DTA_TOKENID_UINT; } else // TOKEN return (OPAL_TOKEN) response[tokenNum][0]; } uint32_t DtaResponse::getLength(uint32_t tokenNum) { return (uint32_t) response[tokenNum].size(); } uint64_t DtaResponse::getUint64(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::getUint64"; if (!(response[tokenNum][0] & 0x80)) { //tiny atom if ((response[tokenNum][0] & 0x40)) { LOG(E) << "unsigned int requested for signed tiny atom"; exit(EXIT_FAILURE); } else { return (uint64_t) (response[tokenNum][0] & 0x3f); } } else if (!(response[tokenNum][0] & 0x40)) { // short atom if ((response[tokenNum][0] & 0x10)) { LOG(E) << "unsigned int requested for signed short atom"; exit(EXIT_FAILURE); } else { uint64_t whatever = 0; if (response[tokenNum].size() > 9) { LOG(E) << "UINT64 with greater than 8 bytes"; } int b = 0; for (uint32_t i = (uint32_t) response[tokenNum].size() - 1; i > 0; i--) { whatever |= ((uint64_t)response[tokenNum][i] << (8 * b)); b++; } return whatever; } } else if (!(response[tokenNum][0] & 0x20)) { // medium atom LOG(E) << "unsigned int requested for medium atom is unsupported"; exit(EXIT_FAILURE); } else if (!(response[tokenNum][0] & 0x10)) { // long atom LOG(E) << "unsigned int requested for long atom is unsupported"; exit(EXIT_FAILURE); } else { // TOKEN LOG(E) << "unsigned int requested for token is unsupported"; exit(EXIT_FAILURE); } } uint32_t DtaResponse::getUint32(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::getUint32"; uint64_t i = getUint64(tokenNum); if (i > 0xffffffff) { LOG(E) << "UINT32 truncated "; } return (uint32_t) i; } uint16_t DtaResponse::getUint16(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::getUint16"; uint64_t i = getUint64(tokenNum); if (i > 0xffff) { LOG(E) << "UINT16 truncated "; } return (uint16_t) i; } uint8_t DtaResponse::getUint8(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::getUint8"; uint64_t i = getUint64(tokenNum); if (i > 0xff) { LOG(E) << "UINT8 truncated "; } return (uint8_t) i; } //int64_t DtaResponse::getSint(uint32_t tokenNum) { // LOG(E) << "DtaResponse::getSint() is not implemented"; //} std::vector DtaResponse::getRawToken(uint32_t tokenNum) { return response[tokenNum]; } std::string DtaResponse::getString(uint32_t tokenNum) { LOG(D1) << "Entering DtaResponse::getString"; std::string s; s.erase(); int overhead = 0; if (!(response[tokenNum][0] & 0x80)) { //tiny atom LOG(E) << "Cannot get a string from a tiny atom"; exit(EXIT_FAILURE); } else if (!(response[tokenNum][0] & 0x40)) { // short atom overhead = 1; } else if (!(response[tokenNum][0] & 0x20)) { // medium atom overhead = 2; } else if (!(response[tokenNum][0] & 0x10)) { // long atom overhead = 4; } else { LOG(E) << "Cannot get a string from a TOKEN"; return s; } for (uint32_t i = overhead; i < response[tokenNum].size(); i++) { s.push_back(response[tokenNum][i]); } return s; } void DtaResponse::getBytes(uint32_t tokenNum, uint8_t bytearray[]) { LOG(D1) << "Entering DtaResponse::getBytes"; int overhead = 0; if (!(response[tokenNum][0] & 0x80)) { //tiny atom LOG(E) << "Cannot get a bytestring from a tiny atom"; exit(EXIT_FAILURE); } else if (!(response[tokenNum][0] & 0x40)) { // short atom overhead = 1; } else if (!(response[tokenNum][0] & 0x20)) { // medium atom overhead = 2; } else if (!(response[tokenNum][0] & 0x10)) { // long atom overhead = 4; } else { LOG(E) << "Cannot get a bytestring from a TOKEN"; exit(EXIT_FAILURE); } for (uint32_t i = overhead; i < response[tokenNum].size(); i++) { bytearray[i - overhead] = response[tokenNum][i]; } } uint32_t DtaResponse::getTokenCount() { LOG(D1) << "Entering DtaResponse::getTokenCount()"; return (uint32_t) response.size(); } DtaResponse::~DtaResponse() { LOG(D1) << "Destroying DtaResponse"; } sedutil-1.20.0/Common/DtaResponse.h000066400000000000000000000057461410717517300171150ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #include #include #include "DtaStructures.h" #include "DtaLexicon.h" /** Object containing the parsed tokens. * a vector of vector that contains each token * returned in the TCG response */ class DtaResponse { public: DtaResponse(); /** constructor * @param buffer the response returned by a TCG command */ DtaResponse(void * buffer); ~DtaResponse(); /** (re)initialize the object using a new buffer * @param buffer the response returned by a TCG command */ void init(void * buffer); /** return the type of token * @param tokenNum the 0 based number of the token*/ OPAL_TOKEN tokenIs(uint32_t tokenNum); /** return the length of a token * @param tokenNum the 0 based number of the token*/ uint32_t getLength(uint32_t tokenNum); /** return an unsigned 64bit integer * @param tokenNum the 0 based number of the token*/ uint64_t getUint64(uint32_t tokenNum); /** return an unsigned 32bit integer * @param tokenNum the 0 based number of the token*/ uint32_t getUint32(uint32_t tokenNum); /** return an unsigned 16bit integer * @param tokenNum the 0 based number of the token*/ uint16_t getUint16(uint32_t tokenNum); /** return an unsigned 8bit integer * @param tokenNum the 0 based number of the token*/ uint8_t getUint8(uint32_t tokenNum); /** return the number of tokens in the response */ uint32_t getTokenCount(); /** return a string of the token * @param tokenNum the 0 based number of the token*/ std::string getString(uint32_t tokenNum); /** return the entire token including TCG token overhead * @param tokenNum the 0 based number of the token*/ std::vector getRawToken(uint32_t tokenNum); /** return the token in an array of uint8_t * @param tokenNum the 0 based number of the token * @param bytearray pointer to array for return data */ void getBytes(uint32_t tokenNum, uint8_t bytearray[]); OPALHeader h; /**< TCG Header fields of the response */ private: std::vector> response; /**< tokenized resonse */ }; sedutil-1.20.0/Common/DtaSession.cpp000066400000000000000000000233531410717517300172670ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include "os.h" #include #include "DtaSession.h" #include "DtaOptions.h" #include "DtaDev.h" #include "DtaCommand.h" #include "DtaResponse.h" #include "DtaEndianFixup.h" #include "DtaHexDump.h" #include "DtaHashPwd.h" #include "DtaStructures.h" using namespace std; DtaSession::DtaSession(DtaDev * device) { LOG(D1) << "Creating DtaSsession()"; sessionauth = 0; d = device; } uint8_t DtaSession::start(OPAL_UID SP) { return (start(SP, NULL, OPAL_UID::OPAL_UID_HEXFF)); } uint8_t DtaSession::start(OPAL_UID SP, char * HostChallenge, OPAL_UID SignAuthority) { LOG(D1) << "Entering DtaSession::startSession "; vector auth; auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); for (int i = 0; i < 8; i++) { auth.push_back(OPALUID[SignAuthority][i]); } return(start(SP, HostChallenge, auth)); } uint8_t DtaSession::authuser() { return sessionauth; } #ifdef MULTISTART uint8_t DtaSession::start(OPAL_UID SP, char * HostChallenge, vector SignAuthority) { vector auth; if ((lastRC = unistart(SP, HostChallenge, SignAuthority)) == 0) { sessionauth = 0; return 0; } else { for (uint8_t i = 1; i < 9; i++) { // { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, /**< USER1 */ auth.clear(); auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); auth.push_back(0x00); auth.push_back(0x00); auth.push_back(0x00); auth.push_back(0x09); auth.push_back(0x00); auth.push_back(0x03); auth.push_back(0x00); auth.push_back(i); if ((lastRC = unistart(SP, HostChallenge, auth)) == 0) { sessionauth = i; return 0; } } } return lastRC; } uint8_t DtaSession::unistart(OPAL_UID SP, char * HostChallenge, vector SignAuthority) #else uint8_t DtaSession::start(OPAL_UID SP, char * HostChallenge, vector SignAuthority) #endif { LOG(D1) << "Entering DtaSession::startSession "; vector hash; lastRC = 0; DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } DtaResponse response; cmd->reset(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::STARTSESSION); cmd->addToken(OPAL_TOKEN::STARTLIST); // [ (Open Bracket) cmd->addToken(105); // HostSessionID : sessionnumber cmd->addToken(SP); // SPID : SP cmd->addToken(OPAL_TINY_ATOM::UINT_01); // write if ((NULL != HostChallenge) && (!d->isEprise())) { cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken(OPAL_TINY_ATOM::UINT_00); if (hashPwd) { hash.clear(); DtaHashPwd(hash, HostChallenge, d); cmd->addToken(hash); } else { cmd->addToken(HostChallenge); } cmd->addToken(OPAL_TOKEN::ENDNAME); cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken(OPAL_TINY_ATOM::UINT_03); cmd->addToken(SignAuthority); cmd->addToken(OPAL_TOKEN::ENDNAME); } // w/o the timeout the session may wedge and require a power-cycle, // e.g., when interrupted by ^C. 60 seconds is inconveniently long, // but revert may require that long to complete. if (d->isEprise()) { cmd->addToken(OPAL_TOKEN::STARTNAME); cmd->addToken("SessionTimeout"); cmd->addToken(60000); cmd->addToken(OPAL_TOKEN::ENDNAME); } cmd->addToken(OPAL_TOKEN::ENDLIST); // ] (Close Bracket) cmd->complete(); if ((lastRC = sendCommand(cmd, response)) != 0) { LOG(E) << "Session start failed rc = " << (int)lastRC; delete cmd; return lastRC; } // call user method SL HSN TSN EL EOD SL 00 00 00 EL // 0 1 2 3 4 5 6 7 8 HSN = SWAP32(response.getUint32(4)); TSN = SWAP32(response.getUint32(5)); delete cmd; if ((NULL != HostChallenge) && (d->isEprise())) { return(authenticate(SignAuthority, HostChallenge)); } return 0; } uint8_t DtaSession::authenticate(vector Authority, char * Challenge) { LOG(D1) << "Entering DtaSession::authenticate "; vector hash; DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create session object "; return DTAERROR_OBJECT_CREATE_FAILED; } DtaResponse response; cmd->reset(OPAL_UID::OPAL_THISSP_UID, d->isEprise() ? OPAL_METHOD::EAUTHENTICATE : OPAL_METHOD::AUTHENTICATE); cmd->addToken(OPAL_TOKEN::STARTLIST); // [ (Open Bracket) cmd->addToken(Authority); if (Challenge && *Challenge) { cmd->addToken(OPAL_TOKEN::STARTNAME); if (d->isEprise()) cmd->addToken("Challenge"); else cmd->addToken(OPAL_TINY_ATOM::UINT_00); if (hashPwd) { hash.clear(); DtaHashPwd(hash, Challenge, d); cmd->addToken(hash); } else cmd->addToken(Challenge); cmd->addToken(OPAL_TOKEN::ENDNAME); } cmd->addToken(OPAL_TOKEN::ENDLIST); // ] (Close Bracket) cmd->complete(); if ((lastRC = sendCommand(cmd, response)) != 0) { LOG(E) << "Session Authenticate failed"; delete cmd; return lastRC; } if (0 == response.getUint8(1)) { LOG(E) << "Session Authenticate failed (response = false)"; delete cmd; return DTAERROR_AUTH_FAILED; } LOG(D1) << "Exiting DtaSession::authenticate "; delete cmd; return 0; } uint8_t DtaSession::sendCommand(DtaCommand * cmd, DtaResponse & response) { LOG(D1) << "Entering DtaSession::sendCommand()"; cmd->setHSN(HSN); cmd->setTSN(TSN); cmd->setcomID(d->comID()); uint8_t exec_rc = d->exec(cmd, response, SecurityProtocol); if (0 != exec_rc) { LOG(E) << "Command failed on exec " << (uint16_t) exec_rc; return exec_rc; } /* * Check out the basics that so that we know we * have a sane reply to work with */ // zero lengths -- these are big endian but it doesn't matter for uint = 0 if ((0 == response.h.cp.length) || (0 == response.h.pkt.length) || (0 == response.h.subpkt.length)) { LOG(E) << "One or more header fields have 0 length"; return DTAERROR_COMMAND_ERROR; } // if we get an endsession response return 0 if (OPAL_TOKEN::ENDOFSESSION == response.tokenIs(0)) { return 0; } // IF we received a method status return it if (!((OPAL_TOKEN::ENDLIST == response.tokenIs(response.getTokenCount() - 1)) && (OPAL_TOKEN::STARTLIST == response.tokenIs(response.getTokenCount() - 5)))) { // no method status so we hope we reported the error someplace else LOG(E) << "Method Status missing"; return DTAERROR_NO_METHOD_STATUS; } if (OPALSTATUSCODE::SUCCESS != response.getUint8(response.getTokenCount() - 4)) { LOG(E) << "method status code " << methodStatus(response.getUint8(response.getTokenCount() - 4)); } return response.getUint8(response.getTokenCount() - 4); } void DtaSession::setProtocol(uint8_t value) { LOG(D1) << "Entering DtaSession::setProtocol"; SecurityProtocol = value; } void DtaSession::dontHashPwd() { LOG(D1) << "Entering DtaSession::setProtocol"; hashPwd = 0; } void DtaSession::expectAbort() { LOG(D1) << "Entering DtaSession::methodStatus()"; willAbort = 1; } char * DtaSession::methodStatus(uint8_t status) { LOG(D1) << "Entering DtaSession::methodStatus()"; switch (status) { case OPALSTATUSCODE::AUTHORITY_LOCKED_OUT: return (char *) "AUTHORITY_LOCKED_OUT"; case OPALSTATUSCODE::FAIL: return (char *) "FAIL"; case OPALSTATUSCODE::INSUFFICIENT_ROWS: return (char *) "INSUFFICIENT_ROWS"; case OPALSTATUSCODE::INSUFFICIENT_SPACE: return (char *) "INSUFFICIENT_SPACE"; case OPALSTATUSCODE::INVALID_FUNCTION: return (char *) "INVALID_FUNCTION"; case OPALSTATUSCODE::INVALID_PARAMETER: return (char *) "INVALID_PARAMETER"; case OPALSTATUSCODE::INVALID_REFERENCE: return (char *) "INVALID_REFERENCE"; case OPALSTATUSCODE::NOT_AUTHORIZED: return (char *) "NOT_AUTHORIZED"; case OPALSTATUSCODE::NO_SESSIONS_AVAILABLE: return (char *) "NO_SESSIONS_AVAILABLE"; case OPALSTATUSCODE::RESPONSE_OVERFLOW: return (char *) "RESPONSE_OVERFLOW"; case OPALSTATUSCODE::SP_BUSY: return (char *) "SP_BUSY"; case OPALSTATUSCODE::SP_DISABLED: return (char *) "SP_DISABLED"; case OPALSTATUSCODE::SP_FAILED: return (char *) "SP_FAILED"; case OPALSTATUSCODE::SP_FROZEN: return (char *) "SP_FROZEN"; case OPALSTATUSCODE::SUCCESS: return (char *) "SUCCESS"; case OPALSTATUSCODE::TPER_MALFUNCTION: return (char *) "TPER_MALFUNCTION"; case OPALSTATUSCODE::TRANSACTION_FAILURE: return (char *) "TRANSACTION_FAILURE"; case OPALSTATUSCODE::UNIQUENESS_CONFLICT: return (char *) "UNIQUENESS_CONFLICT"; default: return (char *) "Unknown status code"; } } DtaSession::~DtaSession() { LOG(D1) << "Destroying DtaSession"; DtaResponse response; if (!willAbort) { DtaCommand *cmd = new DtaCommand(); if (NULL == cmd) { LOG(E) << "Unable to create command object "; } else { cmd->reset(); cmd->addToken(OPAL_TOKEN::ENDOFSESSION); cmd->complete(0); if (sendCommand(cmd, response)) { LOG(E) << "EndSession Failed"; } delete cmd; } } } sedutil-1.20.0/Common/DtaSession.h000066400000000000000000000105441410717517300167320ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once /* * Manage tDtaLexicon */ #include "DtaLexicon.h" #include class DtaCommand; class DtaDev; class DtaResponse; using namespace std; /** Encapsulate the session management functionality */ class DtaSession { public: /** Constructor * @param device the device the session is to be conducted with */ DtaSession(DtaDev * device); /** Destructor ends the session if required */ ~DtaSession(); /** start an anonymous session * @param SP the Security Provider to start the session with */ uint8_t start(OPAL_UID SP); /** Start an authenticated session with any user(1-8) or admint (OPAL only) * @param SP the securitly provider to start the session with * @param HostChallenge the password to start the session * @param SignAuthority the Signing authority (in a simple session this is the user) * */ #ifdef MULTISTART uint8_t unistart(OPAL_UID SP, char * HostChallenge, vector SignAuthority); #endif /** Start an authenticated session (OPAL only) * @param SP the securitly provider to start the session with * @param HostChallenge the password to start the session * @param SignAuthority the Signing authority (in a simple session this is the user) */ uint8_t start(OPAL_UID SP, char * HostChallenge, OPAL_UID SignAuthority); /** Start an authenticated session (OPAL only) * @param SP the securitly provider to start the session with * @param HostChallenge the password to start the session * @param SignAuthority the Signing authority (in a simple session this is the user) * */ uint8_t start(OPAL_UID SP, char * HostChallenge, vector SignAuthority); /** Authenticate an already started session * @param Authority the authority to authenticate * @param Challenge the password */ uint8_t authenticate(vector Authority, char * Challenge); /** assign the security protocol to be used in the sessiion * @param value the security protocol number */ void setProtocol(uint8_t value); /** The password is not to be hashed. * This is used when the factory default password or the PSID password is * used to authenticate a session */ void dontHashPwd(); /** expect the session to abort. * this is used when the method called will abort the session (revert) * to suppress the normal error checking */ void expectAbort(); /** return the authorization the session has started under */ uint8_t authuser(); /** send a command to the device in this session * @param cmd The DtaCommand object * @param response The MesdResponse object */ uint8_t sendCommand(DtaCommand * cmd, DtaResponse & response); private: /** Default constructor, private should never be called */ DtaSession(); /** return a string explaining the method status * @param status the method status code returned */ char * methodStatus(uint8_t status); DtaDev * d; /**< Pointer to device this session is with */ uint32_t bufferpos = 0; /**< psooition in the response buffer the parser is at */ uint32_t TSN = 0; /**< TPer session number */ uint32_t HSN = 0; /**< Host session number */ uint8_t willAbort = 0; /**< Command is expected to abort */ uint8_t hashPwd = 1; /**< hash the password when authenticating */ uint8_t SecurityProtocol = 0x01; /**< The seurity protocol to be used */ uint8_t lastRC; /**< last return code */ uint8_t sessionauth; /** authid for multistart */ }; sedutil-1.20.0/Common/DtaStructures.h000066400000000000000000000345511410717517300174760ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #pragma once #pragma pack(push) #pragma pack(1) #define FC_TPER 0x0001 #define FC_LOCKING 0x0002 #define FC_GEOMETRY 0x0003 #define FC_ENTERPRISE 0x0100 #define FC_DATASTORE 0x0202 #define FC_SINGLEUSER 0x0201 #define FC_OPALV100 0x0200 #define FC_OPALV200 0x0203 /** The Discovery 0 Header. As defined in * Opal SSC Documentation */ typedef struct _Discovery0Header { uint32_t length; /**< the lenght of the header 48 in 2.00.100*/ uint32_t revision; /**< revision of the header 1 in 2.00.100 */ uint32_t reserved01; uint32_t reserved02; // the remainder of the structure is vendor specific and will not be addressed now } Discovery0Header; /** TPer Feature Descriptor. Contains flags indicating support for the * TPer features described in the OPAL specification. The names match the * OPAL terminology */ typedef struct _Discovery0TPerFeatures { uint16_t featureCode; /* 0x0001 in 2.00.100 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; /* big endian uint8_t reserved01 : 1; uint8_t comIDManagement : 1; uint8_t reserved02 : 1; uint8_t streaming : 1; uint8_t bufferManagement : 1; uint8_t acknack : 1; uint8_t async : 1; uint8_t sync : 1; */ uint8_t sync : 1; uint8_t async : 1; uint8_t acknack : 1; uint8_t bufferManagement : 1; uint8_t streaming : 1; uint8_t reserved02 : 1; uint8_t comIDManagement : 1; uint8_t reserved01 : 1; uint32_t reserved03; uint32_t reserved04; uint32_t reserved05; } Discovery0TPerFeatures; /** Locking Feature Descriptor. Contains flags indicating support for the * locking features described in the OPAL specification. The names match the * OPAL terminology */ typedef struct _Discovery0LockingFeatures { uint16_t featureCode; /* 0x0002 in 2.00.100 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; /* Big endian uint8_t reserved01 : 1; uint8_t reserved02 : 1; uint8_t MBRDone : 1; uint8_t MBREnabled : 1; uint8_t mediaEncryption : 1; uint8_t locked : 1; uint8_t lockingEnabled : 1; uint8_t lockingSupported : 1; */ uint8_t lockingSupported : 1; uint8_t lockingEnabled : 1; uint8_t locked : 1; uint8_t mediaEncryption : 1; uint8_t MBREnabled : 1; uint8_t MBRDone : 1; uint8_t reserved01 : 1; uint8_t reserved02 : 1; uint32_t reserved03; uint32_t reserved04; uint32_t reserved05; } Discovery0LockingFeatures; /** Geometry Feature Descriptor. Contains flags indicating support for the * geometry features described in the OPAL specification. The names match the * OPAL terminology */ typedef struct _Discovery0GeometryFeatures { uint16_t featureCode; /* 0x0003 in 2.00.100 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; /* big Endian uint8_t reserved01 : 7; uint8_t align : 1; */ uint8_t align : 1; uint8_t reserved01 : 7; uint8_t reserved02[7]; uint32_t logicalBlockSize; uint64_t alignmentGranularity; uint64_t lowestAlighedLBA; } Discovery0GeometryFeatures; /** Enterprise SSC Feature */ typedef struct _Discovery0EnterpriseSSC { uint16_t featureCode; /* 0x0100 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; uint16_t baseComID; uint16_t numberComIDs; /* big endian uint8_t reserved01 : 7; uint8_t rangeCrossing : 1; */ uint8_t rangeCrossing : 1; uint8_t reserved01 : 7; uint8_t reserved02; uint16_t reserved03; uint32_t reserved04; uint32_t reserved05; } Discovery0EnterpriseSSC; /** Opal V1 feature */ typedef struct _Discovery0OpalV100 { uint16_t featureCode; /* 0x0200 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; uint16_t baseComID; uint16_t numberComIDs; } Discovery0OpalV100; /** Single User Mode feature */ typedef struct _Discovery0SingleUserMode { uint16_t featureCode; /* 0x0201 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; uint32_t numberLockingObjects; /* big endian uint8_t reserved01 : 5; uint8_t policy : 1; uint8_t all : 1; uint8_t any : 1; */ uint8_t any : 1; uint8_t all : 1; uint8_t policy : 1; uint8_t reserved01 : 5; uint8_t reserved02; uint16_t reserved03; uint32_t reserved04; } Discovery0SingleUserMode; /** Additonal Datastores feature . */ typedef struct _Discovery0DatastoreTable { uint16_t featureCode; /* 0x0203 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; uint16_t reserved01; uint16_t maxTables; uint32_t maxSizeTables; uint32_t tableSizeAlignment; } Discovery0DatastoreTable; /** OPAL 2.0 feature */ typedef struct _Discovery0OPALV200 { uint16_t featureCode; /* 0x0203 */ uint8_t reserved_v : 4; uint8_t version : 4; uint8_t length; uint16_t baseCommID; uint16_t numCommIDs; /* big endian uint8_t reserved01 : 7; uint8_t rangeCrossing : 1; */ uint8_t rangeCrossing : 1; uint8_t reserved01 : 7; uint16_t numlockingAdminAuth; uint16_t numlockingUserAuth; uint8_t initialPIN; uint8_t revertedPIN; uint8_t reserved02; uint32_t reserved03; } Discovery0OPALV200; /** Union of features used to parse the discovery 0 response */ union Discovery0Features { Discovery0TPerFeatures TPer; Discovery0LockingFeatures locking; Discovery0GeometryFeatures geometry; Discovery0EnterpriseSSC enterpriseSSC; Discovery0SingleUserMode singleUserMode; Discovery0OPALV200 opalv200; Discovery0OpalV100 opalv100; Discovery0DatastoreTable datastore; }; /** ComPacket (header) for transmissions. */ typedef struct _OPALComPacket { uint32_t reserved0; uint8_t extendedComID[4]; uint32_t outstandingData; uint32_t minTransfer; uint32_t length; } OPALComPacket; /** Packet structure. */ typedef struct _OPALPacket { uint32_t TSN; uint32_t HSN; uint32_t seqNumber; uint16_t reserved0; uint16_t ackType; uint32_t acknowledgement; uint32_t length; } OPALPacket; /** Data sub packet header */ typedef struct _OPALDataSubPacket { uint8_t reserved0[6]; uint16_t kind; uint32_t length; } OPALDataSubPacket; /** header of a response */ typedef struct _OPALHeader { OPALComPacket cp; OPALPacket pkt; OPALDataSubPacket subpkt; } OPALHeader; /** ATA commands needed for TCG storage communication */ typedef enum _ATACOMMAND { IF_RECV = 0x5c, IF_SEND = 0x5e, IDENTIFY = 0xec, } ATACOMMAND; typedef enum _DTA_DEVICE_TYPE { DEVICE_TYPE_ATA, DEVICE_TYPE_SAS, DEVICE_TYPE_NVME, DEVICE_TYPE_USB, DEVICE_TYPE_OTHER, } DTA_DEVICE_TYPE; /** structure to store Disk information. */ typedef struct _OPAL_DiskInfo { // parsed the Function block? uint8_t Unknown; uint8_t VendorSpecific; uint8_t TPer : 1; uint8_t Locking : 1; uint8_t Geometry : 1; uint8_t Enterprise : 1; uint8_t SingleUser : 1; uint8_t DataStore : 1; uint8_t OPAL20 : 1; uint8_t OPAL10 : 1; uint8_t Properties : 1; uint8_t ANY_OPAL_SSC : 1; // values ONLY VALID IF FUNCTION ABOVE IS TRUE!!!!! uint8_t TPer_ACKNACK : 1; uint8_t TPer_async : 1; uint8_t TPer_bufferMgt : 1; uint8_t TPer_comIDMgt : 1; uint8_t TPer_streaming : 1; uint8_t TPer_sync : 1; uint8_t Locking_locked : 1; uint8_t Locking_lockingEnabled : 1; uint8_t Locking_lockingSupported : 1; uint8_t Locking_MBRDone : 1; uint8_t Locking_MBREnabled : 1; uint8_t Locking_mediaEncrypt : 1; uint8_t Geometry_align : 1; uint64_t Geometry_alignmentGranularity; uint32_t Geometry_logicalBlockSize; uint64_t Geometry_lowestAlignedLBA; uint8_t Enterprise_rangeCrossing : 1; uint16_t Enterprise_basecomID; uint16_t Enterprise_numcomID; uint8_t SingleUser_any : 1; uint8_t SingleUser_all : 1; uint8_t SingleUser_policy : 1; uint32_t SingleUser_lockingObjects; uint16_t DataStore_maxTables; uint32_t DataStore_maxTableSize; uint32_t DataStore_alignment; uint16_t OPAL10_basecomID; uint16_t OPAL10_numcomIDs; uint16_t OPAL20_basecomID; uint16_t OPAL20_numcomIDs; uint8_t OPAL20_initialPIN; uint8_t OPAL20_revertedPIN; uint16_t OPAL20_numAdmins; uint16_t OPAL20_numUsers; uint8_t OPAL20_rangeCrossing; // IDENTIFY information DTA_DEVICE_TYPE devType; uint8_t serialNum[20]; uint8_t null0; // make sn a cstring uint8_t firmwareRev[8]; uint8_t null1; // make firmware rev a cstring uint8_t modelNum[40]; uint8_t null2; // make model number a cstring } OPAL_DiskInfo; /** Response returned by ATA Identify */ typedef struct _IDENTIFY_RESPONSE { uint8_t reserved0; uint8_t reserved1 : 7; uint8_t devType : 1; uint8_t reserved2[18]; uint8_t serialNum[20]; uint8_t reserved3[6]; uint8_t firmwareRev[8]; uint8_t modelNum[40]; } IDENTIFY_RESPONSE; typedef struct _UASP_INQUIRY_RESPONSE { uint8_t fill1[20]; char ProductSerial[20]; uint8_t fill2[6]; char ProductRev[8]; char ProductID[40]; } UASP_INQUIRY_RESPONSE; typedef struct _SCSI_INQUIRY_RESPONSE { uint8_t fill1[16]; char ProductID[16]; char ProductRev[4]; } SCSI_INQUIRY_RESPONSE; //////////////////////////////////////////////////////////////////////////////// class CScsiCmdInquiry //////////////////////////////////////////////////////////////////////////////// { public: enum { OPCODE = 0x12, }; uint8_t m_Opcode; // 0 unsigned m_EVPD : 1; // 1 unsigned m_Reserved_1 : 7; uint8_t m_PageCode; // 2 uint16_t m_AllocationLength; // 3 uint8_t m_Control; // 5 } ; // 6 //////////////////////////////////////////////////////////////////////////////// class CScsiCmdInquiry_StandardData //////////////////////////////////////////////////////////////////////////////// { public: unsigned m_PeripheralDeviceType : 5; // 0 unsigned m_PeripheralQualifier : 3; unsigned m_Reserved_1 : 6; // 1 unsigned m_LUCong : 1; unsigned m_RMB : 1; uint8_t m_Version; // 2 unsigned m_ResponseDataFormat : 4; // 3 unsigned m_HiSup : 1; unsigned m_NormACA : 1; unsigned m_Reserved_2 : 1; unsigned m_Reserved_3 : 1; uint8_t m_AdditionalLength; // 4 unsigned m_Protect : 1; // 5 unsigned m_Reserved_4 : 2; unsigned m_3PC : 1; unsigned m_TPGS : 2; unsigned m_ACC : 1; unsigned m_SCCS : 1; unsigned m_ADDR16 : 1; // 6 unsigned m_Reserved_5 : 2; unsigned m_Obsolete_1 : 1; unsigned m_MultiP : 1; unsigned m_VS1 : 1; unsigned m_EncServ : 1; unsigned m_Obsolete_2 : 1; unsigned m_VS2 : 1; // 7 unsigned m_CmdQue : 1; unsigned m_Reserved_6 : 1; unsigned m_Obsolete_3 : 1; unsigned m_Sync : 1; unsigned m_WBus16 : 1; unsigned m_Reserved_7 : 1; unsigned m_Obsolete_4 : 1; uint8_t m_T10VendorId[8]; // 8 uint8_t m_ProductId[16]; // 16 uint8_t m_ProductRevisionLevel[4]; // 32 }; // 36 //////////////////////////////////////////////////////////////////////////////// class CScsiCmdSecurityProtocolIn //////////////////////////////////////////////////////////////////////////////// { public: enum { OPCODE = 0XA2, }; uint8_t m_Opcode; // 0 uint8_t m_SecurityProtocol; // 1 uint16_t m_SecurityProtocolSpecific; // 2 unsigned m_Reserved_1 : 7; // 4 unsigned m_INC_512 : 1; uint8_t m_Reserved_2; // 5 uint32_t m_AllocationLength; // 6 uint8_t m_Reserved_3[1]; // 10 uint8_t m_Control; // 11 }; // 12 //////////////////////////////////////////////////////////////////////////////// class CScsiCmdSecurityProtocolOut //////////////////////////////////////////////////////////////////////////////// { public: enum { OPCODE = 0XB5, }; uint8_t m_Opcode; // 0 uint8_t m_SecurityProtocol; // 1 uint16_t m_SecurityProtocolSpecific; // 2 unsigned m_Reserved_1 : 7; // 4 unsigned m_INC_512 : 1; uint8_t m_Reserved_2; // 5 uint32_t m_TransferLength; // 6 uint8_t m_Reserved_3[1]; // 10 uint8_t m_Control; // 11 }; // 12 #pragma pack(pop)sedutil-1.20.0/Common/LICENSE.txt000066400000000000000000001045131410717517300163300ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . sedutil-1.20.0/Common/ReadMe.txt000066400000000000000000000035741410717517300164100ustar00rootroot00000000000000This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . ***** Warning ****** PROPER USE OF CERTAIN FEATURES OF THIS PROGRAM ***** Warning ****** **WILL** CAUSE AN UNRECOVERABLE LOSS ALL OF THE DATA ON YOUR ***** Warning ****** DRIVE ***** Warning ****** ***** Warning ****** A FAILURE OF AND/OR IMPROPER USE OF THIS PROGRAM ***** Warning ****** COULD CAUSE AN UNRECOVERABLE LOSS ALL OF THE DATA ON YOUR ***** Warning ****** DRIVE AND/OR PREVENT THE DRIVE FROM BEING USED AT ***** Warning ****** ALL EVER AGAIN ***** Warning ****** ***** Warning ****** IF YOU ARE UNSURE OF WHAT YOU ARE DOING THEN ***** Warning ****** *PLEASE* GET SOME HELP USING THIS PROGRAM. ***** Warning ****** You must be administrator/root to run this program In Linux libata.allow_tpm must be set to 1. Either via adding libata.allow_tpm=1 to the kernel flags at boot time or changing the contents of /sys/module/libata/parameters/allow_tpm to a from a "0" to a "1" on a running system. Currently the only operation that a general user would want to use is the PSID revert function see linux/PSIDRevert_LINUX.txt or win32/PSIDRevert_WINDOWS.txt Source code is available on GitHub at https://github.com/Drive-Trust-Alliance/sedutil sedutil-1.20.0/Common/log.h000066400000000000000000000217361410717517300154440ustar00rootroot00000000000000/* * This software is Copyright 2007 Petru Marginean * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to * * * simple logging class discussed in Dr Dobs journal * http://www.drdobbs.com/cpp/logging-in-c/201804215 * * changed the naming a little, converted to safe printf's * and added IFLOG() macro to support calling procedure only * if we are at/above a specific log level */ #ifndef __LOG_H__ #define __LOG_H__ #include #include #include #include #include "DtaOptions.h" inline std::string NowTime(); enum TLogLevel { E, W, I, D, D1, D2, D3, D4 }; template class Log { public: Log(); virtual ~Log(); std::ostringstream& Get(TLogLevel level = I); public: static TLogLevel& Level(); static std::string ToString(TLogLevel level); static TLogLevel FromString(const std::string& level); static TLogLevel FromInt(const int level); protected: std::ostringstream os; private: Log(const Log&); Log& operator =(const Log&); }; template Log::Log() { } template std::ostringstream& Log::Get(TLogLevel level) { os << "- " << NowTime(); os << " " << ToString(level) << ": "; // os << std::string(level > D ? level - D : 0, '\t'); return os; } template Log::~Log() { os << std::endl; T::Output(os.str()); } template TLogLevel& Log::Level() { static TLogLevel Level = D4; return Level; } template std::string Log::ToString(TLogLevel level) { static const char* const buffer[] = {"ERR ", "WARN", "INFO", "DBG ", "DBG1", "DBG2", "DBG3", "DBG4"}; return buffer[level]; } template TLogLevel Log::FromString(const std::string& level) { if (level == "DEBUG4") return D4; if (level == "DEBUG3") return D3; if (level == "DEBUG2") return D2; if (level == "DEBUG1") return D1; if (level == "DEBUG") return D; if (level == "INFO") return I; if (level == "WARN") return W; if (level == "ERROR") return E; Log().Get(W) << "Unknown logging level '" << level << "'. Using INFO level as default."; return I; } template TLogLevel Log::FromInt(const int level) { if (level == 7) return D4; if (level == 6) return D3; if (level == 5) return D2; if (level == 4) return D1; if (level == 3) return D; if (level == 2) return I; if (level == 1) return W; if (level == 0) return E; Log().Get(W) << "Unknown logging level '" << level << "'. Using INFO level as default."; return I; } template class RLog { public: RLog(); virtual ~RLog(); std::ostringstream& Get(TLogLevel level = I, sedutiloutput format = sedutilReadable); public: static TLogLevel& Level(); static std::string ToString(TLogLevel level); static TLogLevel FromString(const std::string& level); static TLogLevel FromInt(const int level); protected: std::ostringstream os; private: RLog(const RLog&); RLog& operator =(const RLog&); TLogLevel curlevel; sedutiloutput outputformat; }; template RLog::RLog() { } template std::ostringstream& RLog::Get(TLogLevel level, sedutiloutput output_format) { curlevel = level; outputformat = output_format; if (output_format == sedutilNormal) { os << "- " << NowTime(); os << " " << ToString(level) << ": "; } // os << std::string(level > D ? level - D : 0, '\t'); return os; } template RLog::~RLog() { os << std::endl; if ((curlevel == I) && (outputformat != sedutilNormal)) T::Output(os.str()); else T::OutputErr(os.str()); } template TLogLevel& RLog::Level() { static TLogLevel Level = D4; return Level; } template std::string RLog::ToString(TLogLevel level) { static const char* const buffer[] = {"ERR ", "WARN", "INFO", "DBG ", "DBG1", "DBG2", "DBG3", "DBG4"}; return buffer[level]; } template TLogLevel RLog::FromString(const std::string& level) { if (level == "DEBUG4") return D4; if (level == "DEBUG3") return D3; if (level == "DEBUG2") return D2; if (level == "DEBUG1") return D1; if (level == "DEBUG") return D; if (level == "INFO") return I; if (level == "WARN") return W; if (level == "ERROR") return E; RLog().Get(W, sedutilNormal) << "Unknown logging level '" << level << "'. Using INFO level as default."; return I; } template TLogLevel RLog::FromInt(const int level) { if (level == 7) return D4; if (level == 6) return D3; if (level == 5) return D2; if (level == 4) return D1; if (level == 3) return D; if (level == 2) return I; if (level == 1) return W; if (level == 0) return E; RLog().Get(W, sedutilNormal) << "Unknown logging level '" << level << "'. Using INFO level as default."; return I; } class Output2FILE { public: static FILE*& Stream(); static FILE*& StreamStdout(); static void Output(const std::string& msg); static void OutputErr(const std::string& msg); }; inline FILE*& Output2FILE::StreamStdout() { static FILE* pStream = stdout; return pStream; } inline FILE*& Output2FILE::Stream() { static FILE* pStream = stderr; return pStream; } inline void Output2FILE::OutputErr(const std::string& msg) { FILE* pStream = Stream(); if (!pStream) return; fprintf(pStream, "%s", msg.c_str()); fflush(pStream); } inline void Output2FILE::Output(const std::string& msg) { FILE* pStream = StreamStdout(); if (!pStream) return; fprintf(pStream, "%s", msg.c_str()); fflush(pStream); } #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) #if defined (BUILDING_FILELOG_DLL) #define FILELOG_DECLSPEC __declspec (dllexport) #elif defined (USING_FILELOG_DLL) #define FILELOG_DECLSPEC __declspec (dllimport) #else #define FILELOG_DECLSPEC #endif // BUILDING_DBSIMPLE_DLL #else #define FILELOG_DECLSPEC #endif // _WIN32 class FILELOG_DECLSPEC CLog : public Log { }; //typedef Log FILELog; class FILELOG_DECLSPEC RCLog : public RLog { }; #ifndef CLOG_MAX_LEVEL #define CLOG_MAX_LEVEL D4 #endif #if 0 #define LOG(level) \ if (level > CLOG_MAX_LEVEL) ;\ else if (level > CLog::Level() || !Output2FILE::Stream()) ; \ else CLog().Get(level) #endif #define IFLOG(level) \ if (level > CLOG_MAX_LEVEL) ;\ else if (level > CLog::Level() || !Output2FILE::Stream()) ; \ else extern sedutiloutput outputFormat; #define LOGX(level) \ if (level > CLOG_MAX_LEVEL) ;\ else if (level > RCLog::Level() || !Output2FILE::Stream()) ; \ else RCLog().Get(level, outputFormat) #define LOG LOGX #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) #include #include inline std::string NowTime() { const int MAX_LEN = 200; char buffer[MAX_LEN]; if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, "HH':'mm':'ss", buffer, MAX_LEN) == 0) return "Error in NowTime()"; char result[100] = {0}; static DWORD first = GetTickCount(); sprintf_s(result, 99, "%s.%03ld", buffer, (long) (GetTickCount() - first) % 1000); return result; } #else #include inline std::string NowTime() { char buffer[11]; time_t t; time(&t); tm r = {0}; strftime(buffer, sizeof (buffer), "%X", localtime_r(&t, &r)); struct timeval tv; gettimeofday(&tv, 0); char result[100] = {0}; snprintf(result, 95, "%s.%03ld", buffer, (long) tv.tv_usec / 1000); return result; } #endif //WIN32 #endif //__LOG_H__ sedutil-1.20.0/Common/pbkdf2/000077500000000000000000000000001410717517300156515ustar00rootroot00000000000000sedutil-1.20.0/Common/pbkdf2/COPYING000066400000000000000000000156101410717517300167070ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. sedutil-1.20.0/Common/pbkdf2/bitops.h000066400000000000000000000153551410717517300173330ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef BITOPS_H #define BITOPS_H #include #include /* Assorted bitwise and common operations used in ciphers. */ /** Circularly rotate right x by n bits. * 0 > n > 32. */ static inline uint32_t rotr32(uint32_t x, unsigned n) { return (x >> n) | (x << (32 - n)); } /** Circularly rotate left x by n bits. * 0 > n > 32. */ static inline uint32_t rotl32(uint32_t x, unsigned n) { return (x << n) | (x >> (32 - n)); } /** Circularly rotate right x by n bits. * 0 > n > 64. */ static inline uint64_t rotr64(uint64_t x, unsigned n) { return (x >> n) | (x << (64 - n)); } /** Circularly rotate left x by n bits. * 0 > n > 64. */ static inline uint64_t rotl64(uint64_t x, unsigned n) { return (x << n) | (x >> (64 - n)); } /** Read 4 bytes from buf, as a 32-bit big endian quantity. */ static inline uint32_t read32_be(const uint8_t buf[4]) { return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); } /** Read 4 bytes from buf, as a 32-bit little endian quantity. */ static inline uint32_t read32_le(const uint8_t buf[4]) { return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0]); } /** Read 8 bytes from buf, as a 64-bit big endian quantity. */ static inline uint64_t read64_be(const uint8_t buf[8]) { uint32_t hi = read32_be(buf), lo = read32_be(buf + 4); return ((uint64_t)hi) << 32 | lo; } /** Read 8 bytes from buf, as a 64-bit little endian quantity. */ static inline uint64_t read64_le(const uint8_t buf[8]) { uint32_t hi = read32_le(buf + 4), lo = read32_le(buf); return ((uint64_t)hi) << 32 | lo; } /** Encode v as a 32-bit big endian quantity into buf. */ static inline void write32_be(uint32_t v, uint8_t buf[4]) { *buf++ = (v >> 24) & 0xff; *buf++ = (v >> 16) & 0xff; *buf++ = (v >> 8) & 0xff; *buf = v & 0xff; } /** Encode v as a 32-bit little endian quantity into buf. */ static inline void write32_le(uint32_t v, uint8_t buf[4]) { *buf++ = v & 0xff; *buf++ = (v >> 8) & 0xff; *buf++ = (v >> 16) & 0xff; *buf = (v >> 24) & 0xff; } /** Encode v as a 64-bit big endian quantity into buf. */ static inline void write64_be(uint64_t v, uint8_t buf[8]) { *buf++ = (v >> 56) & 0xff; *buf++ = (v >> 48) & 0xff; *buf++ = (v >> 40) & 0xff; *buf++ = (v >> 32) & 0xff; *buf++ = (v >> 24) & 0xff; *buf++ = (v >> 16) & 0xff; *buf++ = (v >> 8) & 0xff; *buf = v & 0xff; } /** Encode v as a 64-bit little endian quantity into buf. */ static inline void write64_le(uint64_t v, uint8_t buf[8]) { *buf++ = v & 0xff; *buf++ = (v >> 8) & 0xff; *buf++ = (v >> 16) & 0xff; *buf++ = (v >> 24) & 0xff; *buf++ = (v >> 32) & 0xff; *buf++ = (v >> 40) & 0xff; *buf++ = (v >> 48) & 0xff; *buf = (v >> 56) & 0xff; } /** out = in ^ b8. * out and in may alias. */ static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len) { for (size_t i = 0; i < len; i++) out[i] = in[i] ^ b8; } /** out = x ^ y. * out, x and y may alias. */ static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len) { for (size_t i = 0; i < len; i++) out[i] = x[i] ^ y[i]; } /* out ^= x * out and x may alias. */ static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords) { for (size_t i = 0; i < nwords; i++) out[i] ^= x[i]; } /** Produce 0xffffffff if x == y, zero otherwise, without branching. */ static inline uint32_t mask_u32(uint32_t x, uint32_t y) { uint32_t diff = x ^ y; uint32_t diff_is_zero = ~diff & (diff - 1); return (diff_is_zero >> 31); } /** Product 0xff if x == y, zero otherwise, without branching. */ static inline uint8_t mask_u8(uint32_t x, uint32_t y) { uint32_t diff = x ^ y; uint8_t diff_is_zero = (uint8_t) (~diff & (diff - 1)); return - (diff_is_zero >> 7); } /** Select the ith entry from the given table of n values, in a side channel-silent * way. */ static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n) { uint32_t r = 0; for (uint32_t ii = 0; ii < n; ii++) { uint32_t mask = mask_u32(i, ii); r = (r & ~mask) | (tab[ii] & mask); } return r; } /** Select the ith entry from the given table of n values, in a side channel-silent * way. */ static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n) { uint8_t r = 0; for (uint32_t ii = 0; ii < n; ii++) { uint8_t mask = mask_u8(i, ii); r = (r & ~mask) | (tab[ii] & mask); } return r; } /** Select the ath, bth, cth and dth entries from the given table of n values, * placing the results into a, b, c and d. */ static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d, volatile const uint8_t *tab, uint32_t n) { uint8_t ra = 0, rb = 0, rc = 0, rd = 0; uint8_t mask; for (uint32_t i = 0; i < n; i++) { uint8_t item = tab[i]; mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask); mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask); mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask); mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask); } *a = ra; *b = rb; *c = rc; *d = rd; } /** out ^= if0 or if1, depending on the value of bit. */ static inline void select_xor128(uint32_t out[4], const uint32_t if0[4], const uint32_t if1[4], uint8_t bit) { uint32_t mask1 = mask_u32(bit, 1); uint32_t mask0 = ~mask1; out[0] ^= (if0[0] & mask0) | (if1[0] & mask1); out[1] ^= (if0[1] & mask0) | (if1[1] & mask1); out[2] ^= (if0[2] & mask0) | (if1[2] & mask1); out[3] ^= (if0[3] & mask0) | (if1[3] & mask1); } /** Increments the integer stored at v (of non-zero length len) * with the least significant byte first. */ static inline void incr_le(uint8_t *v, size_t len) { size_t i = 0; while (1) { if (++v[i] != 0) return; i++; if (i == len) return; } } /** Increments the integer stored at v (of non-zero length len) * with the most significant byte last. */ static inline void incr_be(uint8_t *v, size_t len) { len--; while (1) { if (++v[len] != 0) return; if (len == 0) return; len--; } } #endif sedutil-1.20.0/Common/pbkdf2/blockwise.c000066400000000000000000000126501410717517300200030ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include "blockwise.h" #include "bitops.h" #include "handy.h" #include "tassert.h" #include void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock, const void *inp, size_t nbytes, cf_blockwise_in_fn process, void *ctx) { cf_blockwise_accumulate_final(partial, npartial, nblock, inp, nbytes, process, process, ctx); } void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock, const void *inp, size_t nbytes, cf_blockwise_in_fn process, cf_blockwise_in_fn process_final, void *ctx) { const uint8_t *bufin = inp; assert(partial && *npartial < nblock); assert(inp || !nbytes); assert(process && ctx); /* If we have partial data, copy in to buffer. */ if (*npartial && nbytes) { size_t space = nblock - *npartial; size_t taken = MIN(space, nbytes); memcpy(partial + *npartial, bufin, taken); bufin += taken; nbytes -= taken; *npartial += taken; /* If that gives us a full block, process it. */ if (*npartial == nblock) { if (nbytes == 0) process_final(ctx, partial); else process(ctx, partial); *npartial = 0; } } /* now nbytes < nblock or *npartial == 0. */ /* If we have a full block of data, process it directly. */ while (nbytes >= nblock) { /* Partial buffer must be empty, or we're ignoring extant data */ assert(*npartial == 0); if (nbytes == nblock) process_final(ctx, bufin); else process(ctx, bufin); bufin += nblock; nbytes -= nblock; } /* Finally, if we have remaining data, buffer it. */ while (nbytes) { size_t space = nblock - *npartial; size_t taken = MIN(space, nbytes); memcpy(partial + *npartial, bufin, taken); bufin += taken; nbytes -= taken; *npartial += taken; /* If we started with *npartial, we must have copied it * in first. */ assert(*npartial < nblock); } } void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock, const void *inp, void *outp, size_t nbytes, cf_blockwise_out_fn process, void *ctx) { const uint8_t *inb = inp; uint8_t *outb = outp; assert(partial && *npartial < nblock); assert(inp || !nbytes); assert(process && ctx); while (nbytes) { /* If we're out of material, and need more, produce a block. */ if (*npartial == 0) { process(ctx, partial); *npartial = nblock; } size_t offset = nblock - *npartial; size_t taken = MIN(*npartial, nbytes); xor_bb(outb, inb, partial + offset, taken); *npartial -= taken; nbytes -= taken; outb += taken; inb += taken; } } void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial, size_t nblock, uint8_t byte, size_t nbytes, cf_blockwise_in_fn process, void *ctx) { /* only memset the whole of the block once */ int filled = 0; while (nbytes) { size_t start = *npartial; size_t count = MIN(nbytes, nblock - start); if (!filled) memset(partial + start, byte, count); if (start == 0 && count == nblock) filled = 1; if (start + count == nblock) { process(ctx, partial); *npartial = 0; } else { *npartial += count; } nbytes -= count; } } void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial, size_t nblock, uint8_t fbyte, uint8_t mbyte, uint8_t lbyte, size_t nbytes, cf_blockwise_in_fn process, void *ctx) { switch (nbytes) { case 0: break; case 1: fbyte ^= lbyte; cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); break; case 2: cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx); break; default: cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); /* If the middle and last bytes differ, then process the last byte separately. * Otherwise, just extend the middle block size. */ if (lbyte != mbyte) { cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx); cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx); } else { cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx); } break; } } sedutil-1.20.0/Common/pbkdf2/blockwise.h000066400000000000000000000142541410717517300200120ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef BLOCKWISE_H #define BLOCKWISE_H #include #include /* Processing function for cf_blockwise_accumulate. */ typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data); /* Processing function for cf_blockwise_xor. */ typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data); /* This function manages the common abstraction of accumulating input in * a buffer, and processing it when a full block is available. * * partial is the buffer (maintained by the caller) * on entry, npartial is the currently valid count of used bytes on * the front of partial. * on exit, npartial is updated to reflect the status of partial. * nblock is the blocksize to accumulate -- partial must be at least * this long! * input is the new data to process, of length nbytes. * process is the processing function, passed ctx and a pointer * to the data to process (always exactly nblock bytes long!) * which may not neccessarily be the same as partial. */ void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock, const void *input, size_t nbytes, cf_blockwise_in_fn process, void *ctx); /* This function manages the common abstraction of accumulating input in * a buffer, and processing it when a full block is available. * This version supports calling a different processing function for * the last block. * * partial is the buffer (maintained by the caller) * on entry, npartial is the currently valid count of used bytes on * the front of partial. * on exit, npartial is updated to reflect the status of partial. * nblock is the blocksize to accumulate -- partial must be at least * this long! * input is the new data to process, of length nbytes. * process is the processing function, passed ctx and a pointer * to the data to process (always exactly nblock bytes long!) * which may not neccessarily be the same as partial. * process_final is called last (but may not be called at all if * all input is buffered). */ void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock, const void *input, size_t nbytes, cf_blockwise_in_fn process, cf_blockwise_in_fn process_final, void *ctx); /* This function manages XORing an input stream with a keystream * to produce an output stream. The keystream is produced in blocks * (ala a block cipher in counter mode). * * partial is the keystream buffer (maintained by the caller) * on entry, *npartial is the currently valid count of bytes in partial: * unused bytes are at the *end*. So *npartial = 4 means the last four * bytes of partial are usable as keystream. * on exit, npartial is updated to reflect the new state of partial. * nblock is the blocksize to accumulate -- partial must be at least * this long! * input is the new data to process, of length nbytes. * output is where to write input xored with the keystream -- also length * nbytes. * process is the processing function, passed ctx and partial which it * should fill with fresh key stream. */ void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock, const void *input, void *output, size_t nbytes, cf_blockwise_out_fn newblock, void *ctx); /* This function processes a single byte a number of times. It's useful * for padding, and more efficient than calling cf_blockwise_accumulate * a bunch of times. * * partial is the buffer (maintained by the caller) * on entry, npartial is the currently valid count of used bytes on * the front of partial. * on exit, npartial is updated to reflect the status of partial. * nblock is the blocksize to accumulate -- partial must be at least * this long! * process is the processing function, passed ctx and a pointer * to the data to process (always exactly nblock bytes long!) * which may not neccessarily be the same as partial. * byte is the byte to process, nbytes times. */ void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial, size_t nblock, uint8_t byte, size_t nbytes, cf_blockwise_in_fn process, void *ctx); /* This function attempts to process patterns of bytes common in * block cipher padding. * * This takes three bytes: * - a first byte, fbyte, * - a middle byte, mbyte, * - a last byte, lbyte. * * If nbytes is zero, nothing happens. * If nbytes is one, the byte fbyte ^ lbyte is processed. * If nbytes is two, the fbyte then lbyte are processed. * If nbytes is three or more, fbyte, then one or more mbytes, then fbyte * is processed. * * partial is the buffer (maintained by the caller) * on entry, npartial is the currently valid count of used bytes on * the front of partial. * on exit, npartial is updated to reflect the status of partial. * nblock is the blocksize to accumulate -- partial must be at least * this long! * process is the processing function, passed ctx and a pointer * to the data to process (always exactly nblock bytes long!) * which may not neccessarily be the same as partial. */ void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial, size_t nblock, uint8_t fbyte, uint8_t mbyte, uint8_t lbyte, size_t nbytes, cf_blockwise_in_fn process, void *ctx); #endif sedutil-1.20.0/Common/pbkdf2/chash.c000066400000000000000000000014101410717517300170770ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include "chash.h" #include "handy.h" #include "tassert.h" void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out) { cf_chash_ctx ctx; assert(h); h->init(&ctx); h->update(&ctx, m, nm); h->digest(&ctx, out); mem_clean(&ctx, sizeof ctx); } sedutil-1.20.0/Common/pbkdf2/chash.h000066400000000000000000000074241410717517300171170ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef CHASH_H #define CHASH_H #include #include /** * General hash function description * ================================= * This allows us to make use of hash functions without depending * on a specific one. This is useful in implementing, for example, * :doc:`HMAC `. */ /* .. c:type:: cf_chash_init * Hashing initialisation function type. * * Functions of this type should initialise the context in preparation * for hashing a message with `cf_chash_update` functions. * * :rtype: void * :param ctx: hash function-specific context structure. */ typedef void (*cf_chash_init)(void *ctx); /* .. c:type:: cf_chash_update * Hashing data processing function type. * * Functions of this type hash `count` bytes of data at `data`, * updating the contents of `ctx`. * * :rtype: void * :param ctx: hash function-specific context structure. * :param data: input data to hash. * :param count: number of bytes to hash. */ typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count); /* .. c:type:: cf_chash_digest * Hashing completion function type. * * Functions of this type complete a hashing operation, * writing :c:member:`cf_chash.hashsz` bytes to `hash`. * * This function does not change `ctx` -- any padding which needs doing * must be done seperately (in a copy of `ctx`, say). * * This means you can interlave `_update` and `_digest` calls to * learn `H(A)` and `H(A || B)` without hashing `A` twice. * * :rtype: void * :param ctx: hash function-specific context structure. * :param hash: location to write hash result. */ typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash); /* .. c:type:: cf_chash * This type describes an incremental hash function in an abstract way. * * .. c:member:: cf_chash.hashsz * The hash function's output, in bytes. * * .. c:member:: cf_chash.blocksz * The hash function's internal block size, in bytes. * * .. c:member:: cf_chash.init * Context initialisation function. * * .. c:member:: cf_chash:update * Data processing function. * * .. c:member:: cf_chash:digest * Completion function. * */ typedef struct { size_t hashsz; size_t blocksz; cf_chash_init init; cf_chash_update update; cf_chash_digest digest; } cf_chash; /* .. c:macro:: CF_CHASH_MAXCTX * The maximum size of a :c:type:`cf_chash_ctx`. This allows * use to put a structure in automatic storage that can * store working data for any supported hash function. */ #define CF_CHASH_MAXCTX 360 /* .. c:macro:: CF_CHASH_MAXBLK * Maximum hash function block size (in bytes). */ #define CF_CHASH_MAXBLK 128 /* .. c:macro:: CF_MAXHASH * Maximum hash function output (in bytes). */ #define CF_MAXHASH 64 /* .. c:type:: cf_chash_ctx * A type usable with any `cf_chash` as a context. */ typedef union { uint8_t ctx[CF_CHASH_MAXCTX]; uint16_t u16; uint32_t u32; uint64_t u64; } cf_chash_ctx; /* .. c:function:: $DECL * One shot hashing: `out = h(m)`. * * Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes * of result is written to the buffer `out`. * * :param h: hash function description. * :param m: message buffer. * :param nm: message length. * :param out: hash result buffer (written). */ void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out); #endif sedutil-1.20.0/Common/pbkdf2/handy.h000066400000000000000000000033331410717517300171270ustar00rootroot00000000000000#ifndef HANDY_H #define HANDY_H #include #include #include /* * Handy CPP defines and C inline functions. */ /* Evaluates to the number of items in array-type variable arr. */ #define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0]) /* Normal MIN/MAX macros. Evaluate argument expressions only once. */ #define MIN(x, y) (x) < (y) ? (x) : (y) #define MAX(x, y) (x) > (y) ? (x) : (y) /* Swap two values. Uses GCC type inference magic. */ #define SWAP(x, y) \ do { \ typeof (x) __tmp = (x); \ (x) = (y); \ (y) = __tmp; \ } while (0) /** Stringify its argument. */ #define STRINGIFY(x) STRINGIFY_(x) #define STRINGIFY_(x) #x /* Error handling macros. * * These expect a zero = success, non-zero = error convention. */ /** Error: return. * * If the expression fails, return the error from this function. */ #define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0) /** Error: goto. * * If the expression fails, goto x_err. Assumes defn of label * x_err and 'error_type err'. */ #define EG(expr) do { err = (expr); if (err) goto x_err; } while (0) /** Like memset(ptr, 0, len), but not allowed to be removed by * compilers. */ static inline void mem_clean(volatile void *v, size_t len) { if (len) { memset((void *) v, 0, len); (void) *((volatile uint8_t *) v); } } /** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not. * Does not leak length of common prefix through timing. */ static inline unsigned mem_eq(const void *va, const void *vb, size_t len) { const volatile uint8_t *a = va; const volatile uint8_t *b = vb; uint8_t diff = 0; while (len--) { diff |= *a++ ^ *b++; } return !diff; } #endif sedutil-1.20.0/Common/pbkdf2/hmac.c000066400000000000000000000050211410717517300167230ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include "hmac.h" #include "chash.h" #include "bitops.h" #include "handy.h" #include "tassert.h" #include void cf_hmac_init(cf_hmac_ctx *ctx, const cf_chash *hash, const uint8_t *key, size_t nkey) { assert(ctx); assert(hash); mem_clean(ctx, sizeof *ctx); ctx->hash = hash; /* Prepare key: */ uint8_t k[CF_CHASH_MAXBLK]; /* Shorten long keys. */ if (nkey > hash->blocksz) { /* Standard doesn't cover case where blocksz < hashsz. * FIPS186-1 seems to want to append a negative number of zero bytes. * In any case, we only have a k buffer of CF_CHASH_MAXBLK! */ assert(hash->hashsz <= hash->blocksz); cf_hash(hash, key, nkey, k); key = k; nkey = hash->hashsz; } /* Right zero-pad short keys. */ if (k != key) memcpy(k, key, nkey); if (hash->blocksz > nkey) memset(k + nkey, 0, hash->blocksz - nkey); /* Start inner hash computation */ uint8_t blk[CF_CHASH_MAXBLK]; xor_b8(blk, k, 0x36, hash->blocksz); hash->init(&ctx->inner); hash->update(&ctx->inner, blk, hash->blocksz); /* And outer. */ xor_b8(blk, k, 0x5c, hash->blocksz); hash->init(&ctx->outer); hash->update(&ctx->outer, blk, hash->blocksz); mem_clean(blk, sizeof blk); mem_clean(k, sizeof k); } void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata) { assert(ctx && ctx->hash); ctx->hash->update(&ctx->inner, data, ndata); } void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out) { assert(ctx && ctx->hash); assert(out); uint8_t innerh[CF_MAXHASH]; ctx->hash->digest(&ctx->inner, innerh); ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz); ctx->hash->digest(&ctx->outer, out); mem_clean(ctx, sizeof *ctx); } void cf_hmac(const uint8_t *key, size_t nkey, const uint8_t *msg, size_t nmsg, uint8_t *out, const cf_chash *hash) { cf_hmac_ctx ctx; assert(out); assert(hash); cf_hmac_init(&ctx, hash, key, nkey); cf_hmac_update(&ctx, msg, nmsg); cf_hmac_finish(&ctx, out); } sedutil-1.20.0/Common/pbkdf2/hmac.h000066400000000000000000000037661410717517300167460ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef HMAC_H #define HMAC_H #include #include #include "chash.h" /** * HMAC * ==== * This is a one-shot and incremental interface to computing * HMAC with any hash function. * * (Note: HMAC with SHA3 is possible, but is probably not a * sensible thing to want.) */ /* .. c:type:: cf_hmac_ctx * HMAC incremental interface context. * * .. c:member:: cf_hmac_ctx.hash * Hash function description. * * .. c:member:: cf_hmac_ctx.inner * Inner hash computation. * * .. c:member:: cf_hmac_ctx.outer * Outer hash computation. */ typedef struct { const cf_chash *hash; cf_chash_ctx inner; cf_chash_ctx outer; } cf_hmac_ctx; /* .. c:function:: $DECL * Set up ctx for computing a HMAC using the given hash and key. */ void cf_hmac_init(cf_hmac_ctx *ctx, const cf_chash *hash, const uint8_t *key, size_t nkey); /* .. c:function:: $DECL * Input data. */ void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata); /* .. c:function:: $DECL * Finish and compute HMAC. * `ctx->hash->hashsz` bytes are written to `out`. */ void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out); /* .. c:function:: $DECL * One shot interface: compute `HMAC_hash(key, msg)`, writing the * answer (which is `hash->hashsz` long) to `out`. * * This function does not fail. */ void cf_hmac(const uint8_t *key, size_t nkey, const uint8_t *msg, size_t nmsg, uint8_t *out, const cf_chash *hash); #endif sedutil-1.20.0/Common/pbkdf2/pbkdf2.c000066400000000000000000000040401410717517300171630ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include "pbkdf2.h" #include "hmac.h" #include "bitops.h" #include "handy.h" #include "tassert.h" #include static void F(const cf_hmac_ctx *startctx, uint32_t counter, const uint8_t *salt, size_t nsalt, uint32_t iterations, uint8_t *out) { uint8_t U[CF_MAXHASH]; size_t hashsz = startctx->hash->hashsz; uint8_t countbuf[4]; write32_be(counter, countbuf); /* First iteration: * U_1 = PRF(P, S || INT_32_BE(i)) */ cf_hmac_ctx ctx = *startctx; cf_hmac_update(&ctx, salt, nsalt); cf_hmac_update(&ctx, countbuf, sizeof countbuf); cf_hmac_finish(&ctx, U); memcpy(out, U, hashsz); /* Subsequent iterations: * U_c = PRF(P, U_{c-1}) */ for (uint32_t i = 1; i < iterations; i++) { ctx = *startctx; cf_hmac_update(&ctx, U, hashsz); cf_hmac_finish(&ctx, U); xor_bb(out, out, U, hashsz); } } void cf_pbkdf2_hmac(const uint8_t *pw, size_t npw, const uint8_t *salt, size_t nsalt, uint32_t iterations, uint8_t *out, size_t nout, const cf_chash *hash) { uint32_t counter = 1; uint8_t block[CF_MAXHASH]; assert(iterations); assert(out && nout); assert(hash); /* Starting point for inner loop. */ cf_hmac_ctx ctx; cf_hmac_init(&ctx, hash, pw, npw); while (nout) { F(&ctx, counter, salt, nsalt, iterations, block); size_t taken = MIN(nout, hash->hashsz); memcpy(out, block, taken); out += taken; nout -= taken; counter++; } } sedutil-1.20.0/Common/pbkdf2/pbkdf2.h000066400000000000000000000026271410717517300172010ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef PBKDF2_H #define PBKDF2_H #include #include #include "chash.h" /** * PBKDF2-HMAC * =========== * This is PBKDF2 as described by PKCS#5/RFC2898 with HMAC as the PRF. */ /* .. c:function:: $DECL * This computes PBKDF2-HMAC with the given hash functon. * * :param pw: password input buffer. * :param npw: password length. * :param salt: salt input buffer. * :param nsalt: salt length. * :param iterations: non-zero iteration count. Tune this for performance/security tradeoff. * :param out: key material output buffer. `nout` bytes are written here. * :param nout: key material length. * :param hash: hash function description. */ void cf_pbkdf2_hmac(const uint8_t *pw, size_t npw, const uint8_t *salt, size_t nsalt, uint32_t iterations, uint8_t *out, size_t nout, const cf_chash *hash); #endif sedutil-1.20.0/Common/pbkdf2/sha1.c000066400000000000000000000073041410717517300166550ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #include #include "sha1.h" #include "blockwise.h" #include "bitops.h" #include "handy.h" #include "tassert.h" void cf_sha1_init(cf_sha1_context *ctx) { memset(ctx, 0, sizeof *ctx); ctx->H[0] = 0x67452301; ctx->H[1] = 0xefcdab89; ctx->H[2] = 0x98badcfe; ctx->H[3] = 0x10325476; ctx->H[4] = 0xc3d2e1f0; } static void sha1_update_block(void *vctx, const uint8_t *inp) { cf_sha1_context *ctx = vctx; /* This is a 16-word window into the whole W array. */ uint32_t W[16]; uint32_t a = ctx->H[0], b = ctx->H[1], c = ctx->H[2], d = ctx->H[3], e = ctx->H[4], Wt; for (size_t t = 0; t < 80; t++) { /* For W[0..16] we process the input into W. * For W[16..79] we compute the next W value: * * W[t] = (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]) <<< 1 * * But all W indices are reduced mod 16 into our window. */ if (t < 16) { W[t] = Wt = read32_be(inp); inp += 4; } else { Wt = W[(t - 3) % 16] ^ W[(t - 8) % 16] ^ W[(t - 14) % 16] ^ W[(t - 16) % 16]; Wt = rotl32(Wt, 1); W[t % 16] = Wt; } uint32_t f, k; if (t <= 19) { f = (b & c) | (~b & d); k = 0x5a827999; } else if (t <= 39) { f = b ^ c ^ d; k = 0x6ed9eba1; } else if (t <= 59) { f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc; } else { f = b ^ c ^ d; k = 0xca62c1d6; } uint32_t temp = rotl32(a, 5) + f + e + k + Wt; e = d; d = c; c = rotl32(b, 30); b = a; a = temp; } ctx->H[0] += a; ctx->H[1] += b; ctx->H[2] += c; ctx->H[3] += d; ctx->H[4] += e; ctx->blocks++; } void cf_sha1_update(cf_sha1_context *ctx, const void *data, size_t nbytes) { cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial, data, nbytes, sha1_update_block, ctx); } void cf_sha1_digest(const cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]) { cf_sha1_context ours = *ctx; cf_sha1_digest_final(&ours, hash); } void cf_sha1_digest_final(cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]) { uint64_t digested_bytes = ctx->blocks; digested_bytes = digested_bytes * CF_SHA1_BLOCKSZ + ctx->npartial; uint64_t digested_bits = digested_bytes * 8; size_t padbytes = CF_SHA1_BLOCKSZ - ((digested_bytes + 8) % CF_SHA1_BLOCKSZ); /* Hash 0x80 00 ... block first. */ cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial, 0x80, 0x00, 0x00, padbytes, sha1_update_block, ctx); /* Now hash length. */ uint8_t buf[8]; write64_be(digested_bits, buf); cf_sha1_update(ctx, buf, 8); /* We ought to have got our padding calculation right! */ assert(ctx->npartial == 0); write32_be(ctx->H[0], hash + 0); write32_be(ctx->H[1], hash + 4); write32_be(ctx->H[2], hash + 8); write32_be(ctx->H[3], hash + 12); write32_be(ctx->H[4], hash + 16); memset(ctx, 0, sizeof *ctx); } const cf_chash cf_sha1 = { .hashsz = CF_SHA1_HASHSZ, .blocksz = CF_SHA1_BLOCKSZ, .init = (cf_chash_init) cf_sha1_init, .update = (cf_chash_update) cf_sha1_update, .digest = (cf_chash_digest) cf_sha1_digest }; sedutil-1.20.0/Common/pbkdf2/sha1.h000066400000000000000000000047241410717517300166650ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef SHA1_H #define SHA1_H #include #include #include "chash.h" /** * SHA1 * ==== * * You shouldn't use this for anything new. */ /* .. c:macro:: CF_SHA1_HASHSZ * The output size of SHA1: 20 bytes. */ #define CF_SHA1_HASHSZ 20 /* .. c:macro:: CF_SHA1_BLOCKSZ * The block size of SHA1: 64 bytes. */ #define CF_SHA1_BLOCKSZ 64 /* .. c:type:: cf_sha1_context * Incremental SHA1 hashing context. * * .. c:member:: cf_sha1_context.H * Intermediate values. * * .. c:member:: cf_sha1_context.partial * Unprocessed input. * * .. c:member:: cf_sha1_context.npartial * Number of bytes of unprocessed input. * * .. c:member:: cf_sha1_context.blocks * Number of full blocks processed. */ typedef struct { uint32_t H[5]; /* State. */ uint8_t partial[CF_SHA1_BLOCKSZ]; /* Partial block of input. */ uint32_t blocks; /* Number of full blocks processed into H. */ size_t npartial; /* Number of bytes in prefix of partial. */ } cf_sha1_context; /* .. c:function:: $DECL * Sets up `ctx` ready to hash a new message. */ extern void cf_sha1_init(cf_sha1_context *ctx); /* .. c:function:: $DECL * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make * a full block. */ extern void cf_sha1_update(cf_sha1_context *ctx, const void *data, size_t nbytes); /* .. c:function:: $DECL * Finishes the hash operation, writing `CF_SHA1_HASHSZ` bytes to `hash`. * * This leaves `ctx` unchanged. */ extern void cf_sha1_digest(const cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]); /* .. c:function:: $DECL * Finishes the hash operation, writing `CF_SHA1_HASHSZ` bytes to `hash`. * * This destroys `ctx`, but uses less stack than :c:func:`cf_sha1_digest`. */ extern void cf_sha1_digest_final(cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]); /* .. c:var:: cf_sha1 * Abstract interface to SHA1. See :c:type:`cf_chash` for more information. */ extern const cf_chash cf_sha1; #endif sedutil-1.20.0/Common/pbkdf2/tassert.h000066400000000000000000000015161410717517300175120ustar00rootroot00000000000000/* * cifra - embedded cryptography library * Written in 2014 by Joseph Birr-Pixton * * To the extent possible under law, the author(s) have dedicated all * copyright and related and neighboring rights to this software to the * public domain worldwide. This software is distributed without any * warranty. * * You should have received a copy of the CC0 Public Domain Dedication * along with this software. If not, see * . */ #ifndef TASSERT_H #define TASSERT_H /* Tiny assert * ----------- * * This is an assert(3) definition which doesn't include any * strings, but just branches to abort(3) on failure. */ #ifndef FULL_FAT_ASSERT # include # define assert(expr) do { if (!(expr)) abort(); } while (0) #else # include #endif #endif sedutil-1.20.0/Common/sedutil.cpp000066400000000000000000000251271410717517300166650ustar00rootroot00000000000000/* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This file is part of sedutil. sedutil 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. sedutil 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 sedutil. If not, see . * C:E********************************************************************** */ #include #include "os.h" #include "DtaHashPwd.h" #include "DtaOptions.h" #include "DtaLexicon.h" #include "DtaDevGeneric.h" #include "DtaDevOpal1.h" #include "DtaDevOpal2.h" #include "DtaDevEnterprise.h" using namespace std; /* Default to output that omits timestamps and goes to stdout */ sedutiloutput outputFormat = sedutilReadable; int isValidSEDDisk(char *devname) { DtaDev * d; d = new DtaDevGeneric(devname); if (d->isPresent()) { printf("%s", devname); if (d->isAnySSC()) printf(" SED %s%s%s ", (d->isOpal1() ? "1" : "-"), (d->isOpal2() ? "2" : "-"), (d->isEprise() ? "E" : "-")); else printf("%s", " NO --- "); cout << d->getModelNum() << " " << d->getFirmwareRev(); cout << std::endl; } delete d; return 0; } int main(int argc, char * argv[]) { DTA_OPTIONS opts; DtaDev *tempDev = NULL, *d = NULL; if (DtaOptions(argc, argv, &opts)) { return DTAERROR_COMMAND_ERROR; } if ((opts.action != sedutiloption::scan) && (opts.action != sedutiloption::validatePBKDF2) && (opts.action != sedutiloption::isValidSED)) { if (opts.device > (argc - 1)) opts.device = 0; tempDev = new DtaDevGeneric(argv[opts.device]); if (NULL == tempDev) { LOG(E) << "Create device object failed"; return DTAERROR_OBJECT_CREATE_FAILED; } if ((!tempDev->isPresent()) || (!tempDev->isAnySSC())) { LOG(E) << "Invalid or unsupported disk " << argv[opts.device]; delete tempDev; return DTAERROR_COMMAND_ERROR; } if (tempDev->isOpal2()) d = new DtaDevOpal2(argv[opts.device]); else if (tempDev->isOpal1()) d = new DtaDevOpal1(argv[opts.device]); else if (tempDev->isEprise()) d = new DtaDevEnterprise(argv[opts.device]); else { LOG(E) << "Unknown OPAL SSC "; return DTAERROR_INVALID_COMMAND; } delete tempDev; if (NULL == d) { LOG(E) << "Create device object failed"; return DTAERROR_OBJECT_CREATE_FAILED; } // make sure DtaDev::no_hash_passwords is initialized d->no_hash_passwords = opts.no_hash_passwords; d->output_format = opts.output_format; } switch (opts.action) { case sedutiloption::initialSetup: LOG(D) << "Performing initial setup to use sedutil on drive " << argv[opts.device]; return (d->initialSetup(argv[opts.password])); case sedutiloption::setup_SUM: LOG(D) << "Performing SUM setup on drive " << argv[opts.device]; return (d->setup_SUM(opts.lockingrange, atoll(argv[opts.lrstart]), atoll(argv[opts.lrlength]), argv[opts.password], argv[opts.newpassword])); break; case sedutiloption::setSIDPassword: LOG(D) << "Performing setSIDPassword "; return d->setSIDPassword(argv[opts.password], argv[opts.newpassword]); break; case sedutiloption::setAdmin1Pwd: LOG(D) << "Performing setPAdmin1Pwd "; return d->setPassword(argv[opts.password], (char *) "Admin1", argv[opts.newpassword]); break; case sedutiloption::loadPBAimage: LOG(D) << "Loading PBA image " << argv[opts.pbafile] << " to " << opts.device; return d->loadPBA(argv[opts.password], argv[opts.pbafile]); break; case sedutiloption::setLockingRange: LOG(D) << "Setting Locking Range " << (uint16_t) opts.lockingrange << " " << (uint16_t) opts.lockingstate; return d->setLockingRange(opts.lockingrange, opts.lockingstate, argv[opts.password]); break; case sedutiloption::setLockingRange_SUM: LOG(D) << "Setting Locking Range " << (uint16_t)opts.lockingrange << " " << (uint16_t)opts.lockingstate << " in Single User Mode"; return d->setLockingRange_SUM(opts.lockingrange, opts.lockingstate, argv[opts.password]); break; case sedutiloption::enableLockingRange: LOG(D) << "Enabling Locking Range " << (uint16_t) opts.lockingrange; return (d->configureLockingRange(opts.lockingrange, (DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), argv[opts.password])); break; case sedutiloption::disableLockingRange: LOG(D) << "Disabling Locking Range " << (uint16_t) opts.lockingrange; return (d->configureLockingRange(opts.lockingrange, DTA_DISABLELOCKING, argv[opts.password])); break; case sedutiloption::readonlyLockingRange: LOG(D) << "Enabling Locking Range " << (uint16_t)opts.lockingrange; return (d->configureLockingRange(opts.lockingrange, DTA_WRITELOCKINGENABLED, argv[opts.password])); break; case sedutiloption::setupLockingRange: LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange; return (d->setupLockingRange(opts.lockingrange, atoll(argv[opts.lrstart]), atoll(argv[opts.lrlength]), argv[opts.password])); break; case sedutiloption::setupLockingRange_SUM: LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange << " in Single User Mode"; return (d->setupLockingRange_SUM(opts.lockingrange, atoll(argv[opts.lrstart]), atoll(argv[opts.lrlength]), argv[opts.password])); break; case sedutiloption::listLockingRanges: LOG(D) << "List Locking Ranges "; return (d->listLockingRanges(argv[opts.password], -1)); break; case sedutiloption::listLockingRange: LOG(D) << "List Locking Range[" << opts.lockingrange << "]"; return (d->listLockingRanges(argv[opts.password], opts.lockingrange)); break; case sedutiloption::rekeyLockingRange: LOG(D) << "Rekey Locking Range[" << opts.lockingrange << "]"; return (d->rekeyLockingRange(opts.lockingrange, argv[opts.password])); break; case sedutiloption::setBandsEnabled: LOG(D) << "Set bands Enabled"; return (d->setBandsEnabled(-1, argv[opts.password])); break; case sedutiloption::setBandEnabled: LOG(D) << "Set band[" << opts.lockingrange << "] enabled"; return (d->setBandsEnabled(opts.lockingrange, argv[opts.password])); break; case sedutiloption::setMBRDone: LOG(D) << "Setting MBRDone " << (uint16_t)opts.mbrstate; return (d->setMBRDone(opts.mbrstate, argv[opts.password])); break; case sedutiloption::setMBREnable: LOG(D) << "Setting MBREnable " << (uint16_t)opts.mbrstate; return (d->setMBREnable(opts.mbrstate, argv[opts.password])); break; case sedutiloption::enableuser: LOG(D) << "Performing enable user for user " << argv[opts.userid]; return d->enableUser(argv[opts.password], argv[opts.userid]); break; case sedutiloption::activateLockingSP: LOG(D) << "Activating the LockingSP on" << argv[opts.device]; return d->activateLockingSP(argv[opts.password]); break; case sedutiloption::activateLockingSP_SUM: LOG(D) << "Activating the LockingSP on" << argv[opts.device]; return d->activateLockingSP_SUM(opts.lockingrange, argv[opts.password]); break; case sedutiloption::eraseLockingRange_SUM: LOG(D) << "Erasing LockingRange " << opts.lockingrange << " on" << argv[opts.device]; return d->eraseLockingRange_SUM(opts.lockingrange, argv[opts.password]); break; case sedutiloption::query: LOG(D) << "Performing diskquery() on " << argv[opts.device]; d->puke(); return 0; break; case sedutiloption::scan: LOG(D) << "Performing diskScan() "; return(DtaDevOS::diskScan()); break; case sedutiloption::isValidSED: LOG(D) << "Verify whether " << argv[opts.device] << "is valid SED or not"; return isValidSEDDisk(argv[opts.device]); break; case sedutiloption::takeOwnership: LOG(D) << "Taking Ownership of the drive at" << argv[opts.device]; return d->takeOwnership(argv[opts.password]); break; case sedutiloption::revertLockingSP: LOG(D) << "Performing revertLockingSP on " << argv[opts.device]; return d->revertLockingSP(argv[opts.password], 0); break; case sedutiloption::setPassword: LOG(D) << "Performing setPassword for user " << argv[opts.userid]; return d->setPassword(argv[opts.password], argv[opts.userid], argv[opts.newpassword]); break; case sedutiloption::setPassword_SUM: LOG(D) << "Performing setPassword in SUM mode for user " << argv[opts.userid]; return d->setNewPassword_SUM(argv[opts.password], argv[opts.userid], argv[opts.newpassword]); break; case sedutiloption::revertTPer: LOG(D) << "Performing revertTPer on " << argv[opts.device]; return d->revertTPer(argv[opts.password], 0, 0); break; case sedutiloption::revertNoErase: LOG(D) << "Performing revertLockingSP keep global locking range on " << argv[opts.device]; return d->revertLockingSP(argv[opts.password], 1); break; case sedutiloption::validatePBKDF2: LOG(D) << "Performing PBKDF2 validation "; TestPBKDF2(); break; case sedutiloption::yesIreallywanttoERASEALLmydatausingthePSID: case sedutiloption::PSIDrevert: LOG(D) << "Performing a PSID Revert on " << argv[opts.device] << " with password " << argv[opts.password]; return d->revertTPer(argv[opts.password], 1, 0); break; case sedutiloption::PSIDrevertAdminSP: LOG(D) << "Performing a PSID RevertAdminSP on " << argv[opts.device] << " with password " << argv[opts.password]; return d->revertTPer(argv[opts.password], 1, 1); break; case sedutiloption::eraseLockingRange: LOG(D) << "Erase Locking Range " << (uint16_t)opts.lockingrange; return (d->eraseLockingRange(opts.lockingrange, argv[opts.password])); break; case sedutiloption::objDump: LOG(D) << "Performing objDump " ; return d->objDump(argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]); break; case sedutiloption::printDefaultPassword: LOG(D) << "print default password"; return d->printDefaultPassword(); break; case sedutiloption::rawCmd: LOG(D) << "Performing cmdDump "; return d->rawCmd(argv[argc - 7], argv[argc - 6], argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]); break; default: LOG(E) << "Unable to determine what you want to do "; usage(); } return DTAERROR_INVALID_COMMAND; } sedutil-1.20.0/DTA_Contributor_Agreement_v2.docx000066400000000000000000001160031410717517300215310ustar00rootroot00000000000000PK!û˜õ ‹_[Content_Types].xml ¢( ´•ËjÃ0E÷…þƒÑ¶ØJº(¥ÄÉ¢ehúŠ5vD­Òäõ÷ÇŽ)%‰Co Ö̽÷hÒh²Ñe´”5)&ɬT¦HÙ×ì-~dQ@a¤(­”m!°Éøöf4Û:©MHÙÑ=q²hëÀP%·^ ¤__p'²oQ¿ xf ‚Á+6½@.–%F¯Z®Iœ)Xô\÷UQ)SºÒWëü ÂCþH„s¥ÊR¯ŒüÃ7L )w=a¡\¸£†# Uåx@£û az%!š ïBS_[/¹´ÙR“29ms€Óæ¹Ê ÕWnÎÛ B SÒeÒV´PfÏ”Ã,õ<)¯ÒZwBÜ–®OPûvÇ" úhœ;Ö0ÿìâ—y'Hn-‹}œFkÝ Föİw>kà‡ýLüù”'æ%ôAÐXwB ]àP/ŸÄÎæT$uN½uÿmïïïJÓ†xT§OºM$ë‹÷ÕÓ AÈæ»çqüÿÿPK!‘·ïN _rels/.rels ¢( ¬’ÁjÃ0 @ïƒýƒÑ½QÚÁ£N/cÐÛÙ[ILÛØj×þý<ØØ]éaGËÒÓ“ÐzsœFuà”]ð–U н Öù^Ã[û¼x•…¼¥1xÖpâ ›æöfýÊ#I)ʃ‹YŠÏ‘øˆ˜ÍÀå*Döå§ i")ÏÔc$³£žqU×÷˜~3 ™1ÕÖjH[{ª=E¾†ºÎ~ f?±—3-ÂÞ²]ÄTꓸ2j)õ,l0/%œ‘b¬ ð¼Ñêz£¿§Å‰…, ¡ ‰/û|f\ZþçŠæ?6ï!Y´_áoœ]AóÿÿPK!4öö<Ãword/_rels/document.xml.rels ¢( ¬”ËNÃ0E÷HüCä=qR <Ô¤„Ô-„p’ÉCÄãÈžý{¬FyŠÅÂ˹‘ï=ºöd³ý’]ðÚ´ ‡ U¶X'ì-{¾ºg!¥èBÂ`Ø6½¼Ø¼@'È2MÛ›Àº IXCÔ?rnФ0¡êí—Ji)ÈŽºæ½(ÞE |Ek®—,=ñ veÂô®´ùÙ¡‡ÿx«ªj xRÅ^Ò™^)E ­£Ð5P†9­ãçó¯}æ ²Íš™`T\w>ZiëŸó%”­Ä8ì±þ‹aåµ:t°,á8»*ˆ}Æã^æ më3Á$¹ Ö>!K´oѨ¸n}oÆIr^Fä“‚ìÙŃ<ŽƒèÜËŸ Ÿ¿þZÍ…èyð{%H™È»E!“4Bð“_oú ÿÿPK!íFu{ƒ‡Ã´“§E“xùi»qØ<Øl .Œß¼Ã:à{üÒÈgÈ÷ØlÔXì"{£å1SHFBùÀk¡¦€Üf{µZÓ„ƒÍçƒÑI˜÷¦6ëí*ø’õ…œ½B_v‘‹S‹6æa(BàÀ‘{r5´= ‚%së’õÖ)Hœžö&ø7tÆ' ±¼û÷[Fëì Ûìl¥·.d_$~\xÂoê/(+babhªÜßËîY>€Ÿá‰Ü¡6ާ¢ø‘†Â_gÙ¯kµÍƒý†½¼Ï/#5 }y§#jË2åI~”j0„IµÚÍÃöqëõäP jèk÷‹äIùb¢“ø*8—¾ýn9Â÷õø„¼/B¼Afã8_é­I:Íð$Ô‘BAö1þÒhd®ö“QÀ¯C›Û~?’ñi0P¼N/¹‹R‡?Nu #F„Õúü‘˯1ê o¶ŽŽŽÚ[Ž;É/x*²ß—nÜå¶>MIû~ë]»ïôìn?h~I„‘þ|„QÞoõt<|Ph>nŠïÎ8H­-‡ èN¹q/Á hçBïk=Ð?}ªXîœ}°/»7OpÊʽ4ð*RŽ8!$Ø;×°’‘å+±†øe¡èó¡²…€\u"ÕÅão:j¡«  '1³2jyW!ãzƒ_'aüÚ¸·à V 猀 »ŽéuÜ_¼ŽéÛÜ—@ÐxÙfÑžß2F‡RxQºå^è²_ÏWá¥ò};æDŽzÈåæÊ;rÃ, C£‚˜äzÅö£ÿ¿ZÇFã]ëlç¼Ý8ß9huw:ïŽvŽÝ£ƒÆÁqó¼yþßøvóà$‰ü„ª”êªM‹vîLƒO‚8§J¥ Ä=žÂ÷°µG¿c#cwˆ?û0u{¯ð€ð”£¯¢Ö±7þA{€ ‘ÄšñµoFøœ’qŒžE¢c/=4QüAꑃ?õu/ž`Ü4m‚·pÑ ~Pº±Çw~„Øþ„ÿӳ㯙kY²É´ *ú7\]'Ú'wx«Ñ>l4Û¤& *øóO|€'´‚*ö%k@E*Ñ—}èë¨E ´¯`ò× -¼CÍ\Ä€áDø¡pØ´+ûüg7½aP­YíÊc›Kx9‚ç"rÐoÇ(áã@ÃN¯Ý(½((aĆíçÙúŸÄ§xEzÈvœ¢öÎ [Íæ1Û(Ï6¤5é<š$ŠŽï+ €ižs8dw Já’<‘‘4O 3¥SsEZ;k´ŽÎ×¥µÿ{DtÕùdæ‘Ó”Ùú²«[^Ü)(†Ë6¯ÔËBq Ú#ˆ¦(íåQrÚ)Ñß^Nâ–jË:oñ»5é|A[‘R…ó&Î'J&ÎAë°Í`[²êMÙ¿þþÏŒÎþõ÷ÿY·àl$<éPºðº4ÒsÀÐÓŽˆݯϟòÿVÿÙæß% •˜6rU$ô&4ÿžŒÇRÎÉzçοŠmç*pwŸ ÎsŒ!“y,ˆ÷P„I+€_̪é…Ôºßi·Ûg ©uá„ }¬1Gpf*æ7¾Ó·«Ð .Ó:4ùí(³´«öZCÅ×p%NÙuœG@‹¥âÕVcÔ Wå!ˆ%ˆ>ˆ'NžzRXlþÄ1²/ Š,X¸dwÂÄ ™«}Ÿ…Âü–JF»%höª4ÚÁÅa·U©ÑÊOH£Ù[ÔÉ´FsIÄVé´Ó‹îåÕÍÕãÕíÍÃr€ÎÞµ/¦m…wGGÇùÍ¢\jNPÚ[(Ë6òµŠâ»,rF&EŒ¸¥òŸü´µ“áÙzmtφòpUÙ¶¦5ÌÞª Ê^*g7Ÿ–«éucœ|Åja G™Ó_4ÂsFRr@%%ŸvƒXÅ“M‡RwBE¼ÖAª B=.*öF °_\‘€i‹ù^¡õHbÀ¦²D¨ÁÖš¯Rí º`Úöm„ •;œ3Ô³ ä -7OãeÁì·, Ï¡ùÐèd0¤ÆzHƒi5„ûIÇH°‘t£PJl£‘£Þ.u›Ú]ÛY”‚WDcïcI˜—Õ³×8:Ø]OZy¨ÏqTO'=è «»)bˆ±Š‡`ײ3~y’»@‘šûªíÁò@å¼i7þãmJDùKŠ,D°B^š~泞D´Â‹d—”/×Úí‹Æqç]•<<:ož_f¶Ík‘‡sEŸ—ž,°,­zî_M«“4‹ˆê>kóeÞÒ!$­££‹†]¸Ó7ÑJ¦PYŒîÒP€P’Hz#ǰºÀ_9953úÕ¾ë'$U@Â… {yØ88¤DÔ|¡\ú2G§y|xqÄ7ÐÓçÎh/q㨚jæe÷ð¨~Ò,?!Ò´·^%iŒ¤©ÍÇ`¦Ãgp´™²Q†¹:œ°[GÒ )ˆÄ,‹É~‚´(’x¨ú•‰±ê- J²àØEŽ1âyÞ,k-Í‚Ü_DQ£Ëwï,E]-jYKsæØ/±BF¶ÓÚÆ9˜™Íå&©~;k4­ âfòV8˜*÷ÑÈÏzÝ­¡µLR^Í©›‹MÒ×EçóIz8gA‚¬h¼ÅÍ"ûuÙ,e‰I[¢ÛÎQ³³¿°3ÝÇHX`pí=nïihgNìç!Ó²í•1¨e·p?%°§^?ê´ßÍÄAÖtFj°ÑÑA{ÿr^ÓSvï8à›ƒñê4ÃRQØŽÑŠæÊ¼Õšµ-§I¬ÛÕ}1Š@ÆYÊŒÀöŽ" –2š`òƒÅ€ûM"P¿ÚÛ?kÿÎÈüÄÈmö œÌ^k&£/`Bm¬qaÝB<¢Ô_ s¡l¯–­Â J©0o-¿JJ)À6ŸR2;q-Ûv1Éìëy{¶BG¨<%.¢Ñr·±¦µgIhl¼Vy4Jà!/~„†™ ³ÁDžÛ VB"j”FÒ=²lŸÐm%Ã+mšc'бã+À$ëû2°ð¿|r iÁb€×| è'Ò ¸†ð†GF4òhÅr¡Çêå%ÒAø ¹ÎüŒÍ~T¹äæà@€ÅeÂïNÉPyaü Aq‚X3bw[EnB•<¨›'¼Âvè ¡ˆù5Å`]©Cƒ&T¨ÜD'‘XÔǪ* `•‘®¢Z9á£ê ¼úÈ8‘³u‹.r{eÎÖÚ·Ž€Z"‹rø~‡vÈ"$å±Äå4™ûÝàu 8ÄκFÒdW„•IÎÁË̳ÃãFkÿÈ®ü9pê¶ó`í1æÑ´§ú–~×÷^í0«]~B«]€éÕižl‹¼WoÅ„bPÓ£(5S ”.Ijxe±¸Æ}=@ÍC@‚!ÞP÷}=v‡`ƒ 4ö@Pñï  "ˆ’ÞN~}Øíãp¥9C剚1I4”ûåKh—dzÅ Äœ¢˜È@Š"PSÏPx†F‘´Å˜5H#¡Ð¨W(I—`%×B[9‘ ä„‡ÕÛì¸Cè'¿‡zzÚýþNÆÿ,âóMôvíá¨(B€&¨ì M>)ŒÏÁO 1¢A¢c“{ð$fê‰Ú¾R($žº <4VH§o"™p÷¸ð9ÕaìÂÚTEªa…^J.p9ˆ,"4AÔt›„¨c`ƒ _¦ŒñoÊÔǬDvzÐʃWÉÈa`+†!À.J$ü]¬NÑcеµE² ,p* äWé&1ˈÞϘJEðHP†³ DNÃÀ¸ÞšÈi[R›\/Cmc]gY/Z­Ãfmç­Üœ×šoÖzñ‚T‚1?°P~2Ç]\gÄrä¤8béÉœ9~‘2¼‘_±ú¹\ŒÀÒÍyu_Dñ½ (ÀyîǨ‰/ôr|zÖ9ÿó‡ûÛO7åºÛʹ¬T0;—çãÍwõxsý2:ëo¡0ãÜ(z•\‘TÈ+_pLšýÅ©PŽ˜ ›ØzÝ(h1²Å]´©JõRߢ˜¤[£µ|ˆ×Á­¶Îo](–³Ž@qqsûyÛyüؽï^ÞÞwÙâµutT¥k´bиG£Œ¢/”êï¡‘O­0èaôñIÂçP% ®^_ãNÒèd9ò§,«U¨•mŠWDº$§Ýûœÿ£ðÎùíÍEÝÚÁùfY™ŒàB鳋öý ÝŒB1JÁÍŸ$éœÈ¶},Žê}0H‡Kê@*SëAj'­,°[SÊÚ²”ÙhàÝ-@”ãt²²ôrÑ=qq¥|=­­NvÖ¬`"aÔkyA¢¤1„„ø†J°¬<¶Ÿ;^?3}ŽÎ©qCTÎ7CÖ嬤Å»E2ÒU¡ÂÑ2.Ù,K ¹6 8ðšB‰› ·_d€±6¾7Vo t°CyªØ/w0<ž?žìôˆA7#Ÿ´‹‘)/˜²Fæ$Ï0>ôbÌrõD)J °áʽŽª_“€&‰§¢Ð`dw`É0HDár;á ÄÏó™'·B£©jÆgà¨(q‡3h«†¤,â÷ªŒ«<*Œ€òÞ£—kš—ˆýÎÌŽêM5KõnfaÜ :'ĪýòZ-¡ú…ª7ª¥;§ü¡íRñ`Qý¼«|³1óo*m‹Bi~ç¼d£“A‡ZäþaÄ Š·NÈ‹S^è´o;Cñ„ 8rB)rQáq$}ŒÿU£P]Γÿ1`3¢ÖS®*å)@g§#Š0ôiƒFàÛ$+X°\_(XTnKSš.šN‹-‰g £ ô d^4·hÑJÞEhWZ4<Æ s 0 «G=Ôª³~–±)¸l–µIsxó­+ÞñBkºö@Óz§]窿4ñ|Ùn_¤ó™Ù:·¹æWüM°8£õX x}Ä@à󺚫8ꜩ”RiÕ€U¿Éо)äa<&Ú!à r‚¾1_SnÏã(Qñ[Ì“Ëò?ÔFÜ4ƒ®²f6ÿøâò°öd0òÌ+½J÷ù¦2¬¤ß–LR)ÂZ#¦Âr,©¬ PI²F¬d8N«´jÌàL©.[OQ{ü•ðP ).ñàže]¹R•6 K „YU‰êTGdœ ˆÀj ¯l>ì­¬0¼žÅÔ›2.KáŠzçK–«Ö´ÿƵ­»²xþUQËßj<ËëìÎØÐÞ_‚ýU¨añÐÍV·É¼´ÑÂS ëˆ7žvì®"[c ö¬ý?µý|‰”({Y©/›ùóDÔ ðs: cíþ*¥Y“4ëqŠwqߕݹK9F—÷6ZQU;敪`Z7†Ô5ɧ"±Ô¤ì¥‘8Nb?-X{°»¬›Ô¶KAGñÑQ ¶~Õ]Š9†GvÈì¡”´L¥­uÿˆ9 }=‘æMô–vFÛÄL³2´ÿ<)Ìn>Ï.mžÝ|I¥Íd{ašmÆqY@†e2*y—ø%€%ZΑâíif´@)Ö‡;‘P^in´Š8ÀÌe,h Ršiñey²‹Ke[ÔëD'&뻜·¢S2k¥õ¬nË•K¸Ûy¡ÑQô4 š XU™¢;ó(Ë ó­a<¬¦7ÎÎŽEá½¹ñP‘»_<â+R9l«« ¬3\´üÕ&Öz#Îh Šž‰¸kËÍ@’_6ƳW¶ v¿­ÊÇ‚ÿiYÂÓ7‘û}Qóƒw­îAºåÑj–ö†‹‚òŽb$c§Ä)¹ã«íÞÏî2'yE8­’©eq²«FçXrîËÕ<àÚëêÉX(ŸÜ4.SQÆÛÁ]€“Lôêtëtã•ÍcÏ–ñXŽŠÞÌf¬ØöI÷³ƒÏ\céÖªEtúÇ‚ã[–3ø’ãø–ÍÛ5©vD¤{Š-Hte·jÂH³Q8O^Ÿ{8ɺ´ûdT6ñ°º—­Æ»Ê”òÚÞª?ôo˜Z)ÀV_-*ñ}HB ÉÏh¸EŒ6}œ²üŠæ=G«h“ Ö—rß•–å6nÄTƒ50ç˜ìTNj¸mªÛÝR»‘˜TŽË9ü%œ>þԼ㳾¿ë| |¬g5ò—DáxÐ!&8â‹1hÑ@¤©å›Ë&¾zÖ ½šr«óà\=l9g‡«‡mçóÕãÇÛOÎçÎý}çæñªûàÜÞŠ”œÛK§sóçÏW7€*E2plx¯5&R|%½Bþ6±8¸`,ÁìFläxk7P΄¶r]W×ÝmçæöfçêæòþêæC÷‡îÍã¶óC÷þü#@Ö9»º¾zü áíòêñ¦ûðà\¨ç®sÿxuþéºsïÜ}º¿»}èÖ2âÖòü+÷Œ4;‡/t\À¦¬_°V±]i[8›8‹„ùz½Ï õÎYfJÝ’)5oìæ¶šÔzîð½Ú&jÉæ«hHÉLJ:9Ÿ½X ¢9° ±œîFaTŒµìð² Ú p”²jî®ý¹H¬Q<µ'uåÁæé="WÖ, ˆAÜõ'œßBŸŸ\§`âž »õ”’Ñl¢Ö5K+¶žÎX‹xìEj*rÆ{&Þ°È„\€ÅZ©Ç˜¬=¤Z(:jŒ4m§2>Ü™cÒ£-…¸1??ü¬äž‰¢3qâüµöLðó"¶Æ#}½îÔNÿ¶UCÁÙ7*ÕMñ šç ­¯àl'#–ŸÌñw¯àntœoƒ¾íù6¸šn(ŠHbO²8ì¥ ×÷X!ÑtÞ˜RʸÉ?Ëçò©aÌÉžz„—ô‘ˆÁ Ñ6§!yç~1 )"ÜÀ¹m3eô,¥„ëš0.@¾ü]P>Û(“Ó ·–ÊÛ’¾ÇI±AFàí:ô)‹‚Td;š÷Ue5ÐMlU{Nnlðœ°,Äôe¥cÍÐ0ÈŽ*ËŒÁô|+Q}ìG dà¢LÎ図ÏïG.¾"¶ê‚j.#±Õ̉)ò$ʳ5…ìâÎó¼cú]órÄÖ*w =¡Çb+˜GlbÃÆB” u-1ø„R!3uvÜ’¯×0° ²SIô krBØäà¨V­³þ¿Sëk£ÖNDǧ±€]‰T§(•“XÙvbr3QÍX¹¼„J¨1ŽjGæJë’ɼoÖ#,ô7‹§øžfgñ®2Ì42‰ì7½·¤œÐLÅJodƒ¬Ezø€DñÏ÷#Á§%eÅèdáöР®!ϸËê"˜µd³7еK§ß5ÌÛ`°-¯(Œo,º¬Êda0¿‘£0JጱžÚ¥1„‚/3k—û. ðx;±-içÝUEÊû»ÎUÀ Z@1c’˜GãâË4À>¥ŽYT¥ò=>¬›q,&ûÞ¸9.UÊÒ13¤4ùTëBn~%¶pbnœbÌÞÏ'ØäÃ%2‘:c"Øãòq71¾£ü¾¨`ññÿDE ÌÛµSžP¦ Læè7žßeãʲñ3–:™èεYGFÒ}úBùH260E*³ÜH(©D mq^ú AüX¶„«k¸Q$aDŒfÁßáª1º…²gˆ‡s±Â\€‚íâ q'þ”È–|*Y&Ñ*À¤X€ãáHÈ—2;b¡»éÁwt£†Ýû2ÒŒOŠ[ˆ1#£ø G~j׫–[aò w1€D„¾’ÀBªˆO] FäpP+BÐ0kFto$~+‰q! äM öðxÚ`†ÎFz`Cª –噂%£îã·®JÙÛ\>ΤQKÚ¤Šù%©‰Äøp½l¸:˜žå˜›¡7+šÌh»e¸-GÕ¾Kô×híÂRz京*ÆK´€É¬”—±G@ðéÀð¶¡ô}Q0¯¢É²èœR·§´€Qˆl³ÐSÁ°•¶Y¹2Fv¾±— Y |EDé£ÉlK[Ñ–Îù%=7†"+Äp®àšSñ›Ÿ3ƒù~Eg4çp§âWHÅ× ¼>åT;r¡øŸ¨4W÷¤€4N¾¿÷¦ªï\F:KáÇTz'ƒ šøO"P‚È–wã# Aå÷A®“…€ò×àɸä:L9Txrê5rÖðaG3–ÍlLÃÉJ(S-êQ²öŸÈË,D2˜î‰Ò­þfál¦[¤À ûöp»¤é©ØžÙ—Õ}½`µ;ÐfQ/1P—e¼ôèÌü[0io¤OØŒcÔJCŸëF»G”¥èaf@M¥<‰Ž Î?)†o†Ê¾ÖÓÏôü…?úhWÙb{(¼…B ³8^Ñ(ìc“è_ÿVJ¥;ã# àVX.$ð]Û+u3 XJx²LyMð–´ßÐå lâ R7”åjÂãà’J2*~NŒŠ<ÎÁƒÅq£c\-ôË-Q‘é$¡01_QNfí;éM0ãÛXHÛEÆ3Ó~¦ƒsŸ°™¯¤=l?¥?r)Ó~ÓD¶¼•(·hn lɹ8CÉø°èêK “´+Ümϳ_»éÞûyø]¢¿B‰Ž™è™äç2YÞa_ÄpècX8x6GB©ôi…b¨(Ö%R¥ÌM#Êdb €¶éã$ ‘Òò„°ÂóHÓ `Œ!ŒHG›Jl:cÐâ>ÖGHƒif¶˜€÷`­è}ü"†óü…,x>ÊFq¼ÅF³ãÄmq Q¤Ól¥÷–Ò=ÕÀÁh¬$‘q‘AN°§ˆ•è3sß싯ÐËwRÕ85ï¥é¸šË'Ý5/Îp¿g8jðìn}Ì*!Ê$‘2¬`žOg?vþ„ïÔYˆ­ÚêÕW&НU ³ã 8âÜíÞî:gú«³¼ß>~зŽy£Zú£Öè3èÜu§Ùní¿Ž9Ô_já߉ãàÖ¥7 Öý®A '!¼…Ò÷b°HŠ”„‡ª'<)’Zïw¯ôö¶sÞ½}fD6/÷ÇÏÀÜ9 ~Û5~!¹“•U-‘=?Íÿï÷&„^ûTVHß§ò-ù/ço+µZÍU„}#H¾‰¤Ñ`¨ŽfUÍL±yå{S*f&(ïûɯžÇ»šÒúYŒØ(Gh±·œ!¿Ó6Ñ.zà#pp)JÉì@úMêtà†pÐSÁ°l¼iOW¿²ÓC¿ÏXű%ÆÀØÝøPÝÿúíøÁð{ìðÛðCÈS°}£ÕO×ù%F|=þz¶UüõR`i5‡£^ö0DðÁ¹.lÈ¿Õ5“¼ÄÜž‘}  ŒÏf)5:½cãä”b  &{ü "ƒ¢ÿ€ &ÿ*{y°döÛ—X·;‡gíÊxå'4¢½UC¬Õ:þ¯Wn:Ÿî»à;|è:—·××·Ÿþ¶O/õ‹à‰ >Ä¡d¤þ-&g!Z”нºÁ°´™ô3~*áö’c®e¦ÊŒ_eɰé¼AðÁsIÓ”[OúzŒOmÛ²§ 9ü]ÑÄÔÚ”ð›,zÜóí+ˆz~I’>b<þƒQV•ÂãÏðhŒ½ek,Àw˜ÏôÒ™6€ûˆ®4Î’:ØMô«íÏJ8úíj_›bçh4¬÷fODZ­÷.Ç[ÖzU°:òã&/ÿ¸ÎËHYe”÷ük­¿¤}5:¹E~¯Ç¨Ë#x•?<×~2 ÏÓÔ$ÐÏ@adW?òUú=º"M!áÏü…>"¡ƒÃ£6O¶ò6w‘¾£L™Ã¤x÷/š}{Æ’U«sÄrú8vùßôÊ’6à¤Ôí} äSÇÇ@Û!ÓTÚ¡íb}þµÀÓ@5{YüÁ«sjùSãrùkA–Ì3<ÞÌZ)ÿ+ÿÿìVñš0þWHÚ%Ë (x1IÏ‘œHËrûeA¨È‚@JÕsýÚRT¦wËn—Ë$¡´ïµ_ßûÞGaÓ#æ`âøžÝð'ÞmkC ¬Åæ-m$z—Iä@–5¨÷50;1¯3i[ð–„Ü-Z—ƒð3…Ù £w5@»d[ DOh1ÿ¦IœQû:H 0Ë É—ÌÃá*ˆâDµÉBó`•’cËLmKí6º Æì{öè“/¹÷ð ü(ÙÎàZú0˜Œ]è<¾{T§8&ÿ´%ÁUüßÂ:½eá:=á>?¾øFoÉúÔ9Ðð†=éëó×?+ª?Mï9yÝuÍ:sy5bl0×ðüB^¯@9àß‚>¥^\/Tà]%öþ)^N±ßAÑ-UÕ«^•’ô´L{e„4‘£á5¦ÇuaÌošŸÏ4b¾²~gEòÁÿ€èÃUŒ2$¯¥»c”¦Û‹*ÿª*}ۿߟÿ¹0›d &“‹÷b<ÇE'ʳôMäqüªýÎP§P„‡/)QH܆6šë¦ÔϬ²¦ËŠÆÕ1ÏsªÍFYˆö\V; ÷’ÈØŽnDXñô{E¾¢ª™A/h_»¡}1a°H^ «ò8‰d7ª ²¦h¾÷-P!¼Váí†ñŠð¡Ø*ÌÓ’ZÅÃæps”‡#œD :É›FØÖ¹·U³Ä»³<Úò]²ZÒ×ÂüÿÿPK! æÎšá‘word/footnotes.xmlÌ”ÍnÛ0 Çïö†î‰ì ËV#N1Ô[Ñ[Ñ® Êr,ÔIŽ›·å¯dm¤ÍeË”Èÿ$m­®^Tm…utF’yL"¡9Ro2òøç÷쉜gº`5h‘‘päjýõ˪MK¯Á !C»´5<#•÷&¥ÔñJ(ææJr J?ç (”¥ä‚¶` ºˆ“¸{3¸p^3½eŽ 8õ–Fh<,Á*æÑ´ª˜}nÌ é†yù$kéwÈŽ—#2ÒXˆÙ$(„¤½ a#ì)yûx£„ö]FjE@»Jš}Ÿ¥áa5B¶ÇŠØªzôkMrqÞ rËZ\öÀSä}ª{åljI|ÂDbŠ8E¿9G%ŠI½Oü©Ö47ùö1Àâ5ÀlÎÎ…Æìiò<Ú­~žXá×þkòaiî<13ø*žÞn4XöT£"Y„]ÂgMÖWNÔ¦~gÐà Ã,ó` nÉ"#³¤s4hâVÜg$Ž/¯—¿’qp¨e(ÙêbZÜ5A1k<ºÝÐɽgŒ:û#Ûtß!¥×²ã ½ÔM÷¦Ü?Ï4þ‰¾*ùHÒóÜmÿÿÿPK!I©a©±‡ word/footer1.xmlìVÛRÛ0}ïLÿA£§ö|„ÔC‡2<”fJøÙ–ƒn•ä„ðõ]Ù±“”B)Ìt¦/‘´Ò9{V»ZçøäŽ34£ÚRôq°ïcDE*³BLúøzüe¯‡‘±Dd„IAûxA >¼w.µˆ–{­ ‰jAË¡AèmüÖ¡LKN…­6›6ÇRcs–ÅS¢Q;/8OèzÇòäSþVL…0VéÝ#A Ñçó³*Šöà›Ec¨"šXºÐz†c?†õ#û­ !GZÊ|×tÞ6'Td2òØeÛøç æòú««™+ô¿jþVÕ¸~ÓôÀ¶ÛÕËGͯРw¢•£?ÿÿPK!ªR%ß#‹word/theme/theme1.xmlìYM‹7¾úÄÜÍøc‰7Øc;i³›„ì&%GyFžQ¬IÞ]%9 ¥ié¡Þz(m ô’þšmSÚòªÑxlÉ–YÚl`)YÃZÏûêÑûJ4žËWNŽ㘦§z©â”4ÄiÔqîK-pÓš¢Ž3Gܹ²ûá—ᎈQ‚€´Oùì8±Ór™²òKtŠRÙ7¦,BVYT<–~R®U*rqê€&ÒíÍñf.ÝÂù€È©àYC@ØAæ NªÙŸsŸ0pIÇ‘ã„ôøÈ…ìè8õç”w/——FDl±Õì†êoa·0'5eÇ¢ÑÒÐu=·Ñ]úW"6qƒæ 1h,ý) 9Óœ‹Žõzí^ß[`5P^´øî7ûõª×ü×7ð]/ûxÊ‹î~8ôW1Ô@yѳĤYó]¯@y±±oVº}·ià(&8l +^£î³]BÆ”\³ÂÛž;lÖ𪬭®Ü>ÛÖZïS6”•\(p Ä|ŠÆ08}ô³ÅêL#Ýêõ÷_üýôSð×óï^?ùÊŽç:þ÷Ÿ>ûí×/í@¡_}ýìÏ^}óùŸ?<±À» Žtø!N7Ð1¸M91ËhÄþÅa ±nÑM#S˜ÙXÐèsH ×Cfï2)6àÕÙ}ƒðAÌf[€×ãÄîSJz”Yçt=KÂ,샳™Ž» á‘ml-¿ƒÙT®wlséÇÈ y‹È”Ã¥H€¬N²˜ÝÃØˆë>åt,À= z[CrˆGÆjZ]ÉÌËÜFPæÛˆÍþ]Ð£Äæ¾ŽL¤ÜØ\"b„ñ*œ ˜XÄèÈ=(bɃ9 Œ€s!3!BÁ DœÛln²¹A÷º”{Ú÷É<1‘Là‰ ¹)Õ‘}:ñc˜L­œqëØøD.QnQa%AÍ’Õe`º5Ýw12Ò}öÞ¾#•Õ¾@²ž³m DÍý8'cˆ”óòšž'8=SÜ×dÝ{·².…ôÕ·Oíº{!½Ë°uG­Ëø6ܺxû”…øâkwÎÒ[Hn ô½t¿—îÿ½toÛÏç/Ø+V—øâª®Ü$[ïícLȘ´Ç•ºs9½p(UE-¦±,.†3pƒª Ÿ`Äp*‡©ª"¾pq0¥\žªÙê;ë ³dŸ†ykµZ<™J(Víò|)Úåi$òÖFsõ¶t¯j‘zT.d¶ÿ†„6˜I¢n!Ñ,Ï ¡fv.,Ú­ÌýVêk‘¹ÿÌ~ÔðÜœ‘\o 0ËSn_d÷Ü3½-˜æ´k–éµ3®ç“iƒ„¶ÜLÚ2ŒaˆÖ›Ï9×íUJ zY(6i4[ï"×™ˆ¬iIÍ8–{®îI7œvœ±¼Êb2•þx¦›DiÇ Ä"ÐÿEY¦Œ‹>äqS]ùü,'r­ëi éŠ[µÖÌæxAɵ+/rêKO2Q ¶´¬ª²/wbí}KpV¡3Iú ÁˆÌØm(å5«YCÌÅ2š!fÚâ^EqM®[ÑøÅlµE!™Æpq¢èbžÃUyIG›‡bº>+³¾˜Ì(Ê’ôÖ§îÙFY‡&š[ìÔ´ëÇ»;ä5V+Ý7XåÒ½®uíBë¶o hÔVƒÔ2Æj«V“Ú9^´á–KsÛqÞ§ÁúªÍˆâ^©j¯&èè¾\ù}y]ÁUt"ŸüâGå\ Tk¡.'Ìî8*^×õkž_ª´¼AÉ­»•RËëÖK]Ï«W^µÒïÕÊ ˆ8©zùØCùHd ~>N¶‘®¾!ŠàFÏx§ Šúʈæñ7|Ä5A-Z´høñ¤“NrŽ!]ýC ‚³#æàAŸ{î¹±ÅÆ&‚vŸrÞá ÌÀñI >ãêÕ«‡ù˜!šÀ ((ùœ·Æò¶Q»Êà\Oä ñv h.×ì‘“÷Úk¯±ç4ÆŸS$ÂzNÈç9žž#°M&%®6ÙNm¼?–ÀV¾€QeœñÆo´#æ ÌEÙq\I’À\cÑ8RØÇ>ö1;b9Î…Ç•f”ðvù‘CãØŠ&“ÔF¸Æ"Áù˜"¨ÿꫯG"œ+£¸O?ý´éÍç"Ô¹Ú|È9RÃŒýÈ™hÙó‚=†ø?þñÇžs%Ï<óŒsœl3A‘œ±g Œtµ—ÑÀãÁÑÀ¢àäó*PPÔ7÷ß|BQp/¿üòho—mïç}® –/_>÷xø_ ŸX‘m ¾  cø28õ—Ñ  Ê0˜/ă£wÝu×ÑPQP˜/Š‚ãÐX>‡”Á˜oä JKHP†ÂÀ <¸ªhƒ2¨vŒ˜A”!ÞŽ‘É2°ÚƒÒ¤„w„Y$vnùÖ+ì¥ø»>¥aïâøsöÈ€*F)ƒ­®€xP4¦È2(O`-4°J0È!ÊÀÆžÑõqË´k=¢Ž€ ®>ô˜žûþ—´‘eû‡fGL¾mà ‘®v—®ñC@`†QP†¢€P×@ï6kâ Ê ƒâ¥E¬Y³fb,Nm2 \YN–†€æÊçUP¼M>v±ï¾û:ÇÓsÞÆ­|_€Ú ò9‡d ±.%-h)Aí2 ‚Æò9ü1g¢…O¤ ü±„ GJ¼Aq]hÆÉ1\Iå ªŒ#%•ƒ¢ò“c¸’JAÉ?öô¥v¤d²ešH®?e9Ö@mHI© Š"øxzŒDeÔ‚æJ­ô¦š,Ÿûãùs’ÞkàŒµðwZøÄ3Î8cì9Æ‘¯}íkG übôŒrVV×: H6|DƒRæZà ¢öáù@ÔÆo<ê×zÜqÇÁvÒ€¢¾¹ÿà20õóqòãþáŽAŠ2Ì?À;y`õ—Ñ0ówç È0þl„3Ц( ÃdË>Xƃ#h<ŸÇ È€[ðIEiÑdp÷ ÅÀ¡¸w€f‘4kÅÛ-"Y•+Q.‹R/fúÅ"fl•VàP0üM¥Fáo08ËPj&Úœ.IZ;ôÆׂâ!hÚ ]Ò…\Ó§tIR‹zMj$Z]W"׈í袸–Â5…#ÐbèbHŽœ[§c Ë"-…ó°MF—CržËÿùŸÿí>Ï?ÿ|Ø^ätY¤Å9×2Ö‚£Ë! 9/•h¯ûï¿ßÙÇ.‹´¸æ²UæÐå_iØ~ûíGe,CÖ.‹´È9lö<è‚H‚À-êK¥ÜS>GAÅÀË"B/Š2NËe—]×pi@íäÏ%ªhé¢üq¸iˆ1Aë‡:¢à’ˆ èÑfFõ‘\ù™$õÉR-ê‘h­W»ùù5o—ý¨Ô¢éÚ€¿òÊ+c}\š1œ¢Kâð1!jPr-ŽÚ¹Ðxþ\{I>žæ¼ï}ï{Îû©Í‡j”\Xc(h nh¾FY\šÔ‚æjô‘ÅeÐÜÐ|>’]–Qƒ¬IEjAs}jhì²B ·v,¢ݨh’2ÿwãÍå}¡jH~Y¤a·Ýv{^¹6ª– ¨ÑF¡Æía,êã†àMŸ°þåç‡Ï‹6äÏy?rï½÷Ž+ZKcè£KB~¥ƒ g/]’Ô€6&}ý©$|m²_[ ‹" W3¦ ‡üò—ð’HĨ.8]–‘àÿæ’4mZù\þ˜ž¼K Ë! >¾×q|—|‘@f$žzꩉ¹ÒÇ{ ¶4íôüºë®›]¸páX_‘º’àóä7„ÎðIF]˜qffÆŽ˜œëSÎá?û@öiå Ë! >×õ]³ã«ø"F]É‘óSÊAÃ%øü(ßïlà‹ tYR‰\«Œt!H‚¯¥ùþkƒú²¾‰‘@—DÖº’à±k/‰¾,‚oj$š¸$IìK"J_Áƒ0æ­ì%ÑN—ãEU/‰È÷„Ò_V¿¬¥K—ÚGÕ‰rYT@sÃ\TÌØ*¯BÁù?yr€Çf¬J¥x tQüK“ã7}U ÑX…Ò³yü¢ä×rÕ]ûZ+«±,¥fòÑE5vaò¢"_Xð,¾aÑE‘µáº(rÝJÐ ¾‘æ¢H|=N|EP¯ PæT¹(¾NUÇXùf|AÒ…ë ÉÖ^‡ÏOá肤 ×pàÅ ­Q|nŽ.‰; p> p_(ä¢nºé¦±¹u;]w€s.ÀÙ˹(>¯È±Æ 6Ø`8Ç€ú¥c ‹"ÎeÀ>ÑwQ÷­|vØoàó\jÇ!ËÌ.ŠàœÇ˜hå|µný\¿Ï“¢~B¶‡ªYcº(r€sže¬…ô]ÔÇN¾vØoàórŒ|®Íámü1rº(r€sÞ€Ñ3> F:í´ÓFå8Ãa‡6üÈÛ‹Dcyìrº(r€k[anPÌb®SV¾öÏ~ö³±¾"‡¬ü=|Q䀱ñ–ñgtA$Á(2dlYåò9wº$. 貎=å‡Ã~D.jâ.‰ÀË2 Ë"PÜeË–ÁvŸ4¦È9Cžþ¬ú¢ ÎË2”¹(ÒÔ>ÔÎ5¿V"´WŽ‘Ï¹#”e(¼,¿,×wÍP»Ëª 5I ýÜŠ‹2EîÚ>î°ÃýÒX<ÿüópýG(.ÊPé²Î:ë¬Ñcêÿ÷ÿ÷Q›4h¤klêÑh#£á‰'ž€}\‚?®‚YçÒK/=.k•/‹,C ¶2 ux[¨ZT#ßÿþ÷ÃM4rŠú´ðùæû€ÞN¨«E5m`4l¾ùæ°”øú‹àóøE¼?D-•.‹tq¡ÇáãÑEø—hÜ}÷Ý7l÷Qê²d›|ÎÛ]=ùä“í£9ø8×E|,Ò5Fƒj”kaþœ÷S›4‡Ó…ñ~ßEøxÒÕÎÕà…æ®vržKÍEÐ\*_–ËÐ|®ö¢ §œr \ç†V\–¬a>Ð>54~Yh.2äÂÐ|Ÿ¿,ó[þÑ|ih¾O _–Áwa¡ 5|jÈâ²Ð|©4W£ï¨ù—‹ûÔÂçø¾áRš§QƒjZÜç׿þu;Û O=0…Ü<'øÞîBŽ×ª!Ùe‹àãBÿ S„«UC#—ÅÇ”ý›9BŽÑª%ée%¼/äoæ>×(‘ýZµ¨G¢M4rx{èE| #!ÛCÔ’ü²Œ=/{Q„\›?u§v®¡¡–Ë2U/Š 5å>¡†4mblÐFþ):Ÿ!xG/»þÓ³çÝzîð1ÚŒ»ÿþûÇP¿1hm©oÁ¿ñ¼ˆÂQæ¢äwÒmŠú\–­Å¥1<òÈDŸÔ€¾Sß…s¿(ã÷uÕ°mJ¨Ï¥4×¥ùaBúЇ†]s ~Y¾ ƒ½ò¢HmnD}¨-…hÔFäE‘.&z\E®Šžç".ŠDŒµÒ7_£K" D†ÆB  â"F­ò›¯ÑE‘Bêêwµ‡X´†¯Ï€.‡ks £g|Q„.Š$ä<òðß½çž{`Ÿ´h²h õ×®];ìG—Ã5È¹ÄØNhº(’ó\ºÆÊöÏ|æ3mô\~Ôø½ï}o8Þ€.ˆ4ȹœñgÐ`tQ$!ç!]ãd»|.%PŸ”ƒ.ˆ4Í5L¶ @“ÐE‘„œ‡ÔŽ3ʱü9ì’˜9õTxA¤Á5—ƒ[ Éè¢HŽœ"Ÿ×]w9û|èr¸×\‰»gZ]É‘sµþÙŸýl×ÊA—Ã5Í—÷@‹¡‹âräü”3çœ/‡kpÍwá1-Š.‰+‘kÄòôÓO·;Ì.FjëhЀG—$EȵÊ(A—‚4øÖr¡9m‚.HêC®+Õ€.Fj(³66zÚ ]Y'è‚HŠ=„ðЦM_‘ê¢ åf @›7}QDŠ‹2”Ÿ9ÑôE±/ÊPmö€˜ÁÄ&vlQN+˜ÄŒ-ÏfJYô—Õ“„>±z’UbÑÿäsýKHŽðO`ætoYDÂ/FÚƒ‘ %mšF#@BÒÏð2ðŸƒ3õ˜ŸôË@wÇmŠFvF@Ê„’N-èGG3Ð]rë¦ÖÑI_BI§ÍÏ"g »åÖE-;¡’¡ %í,ÚnÏe »æ¦&éè@dÕ„’Æ„ÿ ZŸßüæ7í¬H”I()ÅÌME’•ÑÈØ Ej@ñÔ©”$Ud x¸±‰º" ˜¬³B¡ýsÖɃ q„Ê@ûsce% +¡î¸÷I»Ê$hß6ë%Mˆ ´/·*•V@‘1êë—ÜjWí×e!(q´2Ð~ܲ”š‰ c$핣Ė[n û« AÉ£‘öâ†4mHVM¨ãOý‘=Ú§Œ'“BƒùxÛm·Çrë­·®9J ´W‹j$Ú€¬šP´OUS­ëÒ°ß~ûÁ¾ØN€’G#íÃõQ8-HVM¨»~õ”=Ú'Ä¢58o}ë[ᘘP»”ÆÝ|óÍÃÇ9Fë(y42Ð>\°-@¦ø;Ú§Œ¾µPÿ›ßüæèÿ{DûHwÙeç8W»Ö Pòhd }¸^$§„"dûüÇÀvrÁ‚Ã~ê¯KÂ<þéOjŸÍÎzè¡öQœø&@É£‘ö1J`bfBŒ„úðÿ¹Ú®0‡ ªŠÎûsôÆoœh;á„T±kÆpù¦!(q´2h}…‰E dÑ*á‡öYf¼õå®/nõiœ%ŽV`G7(qŠäì¼óÎðÀ Ûn»-ìëºù£,ʺfÍšáz#PÒøT”XJ")²Œ†+VÀ¾ªÆà…^€k—Õ€ÚIõ9Jd •n%”‘ƒVÕªëÖ ŠAã»ßýn8ß°råʉöÇ@‰D–$Ê-WM*Â<^´hÑèqLsŦ‘@}e#RBÉn‰Æ"乃b®"±ñÆÃ~äŠHrûèHó•šµñÇeÍùÃÜÑB•ëÈçE¦ úªo{ÛÛ`ð Ô§Qâ믓P2¦_|Ñö†[Ž—Ïo½uîKŽx›ËD_^ÆÐµ$h Y7(¡È²Õ‹’žÞô¦7 16QWD§ÖšC¦&$¡$hŽË¯|å+°=Ô˜4’X„yü…/|Á> »Lch>›* ÅAó˨]+&ÑVCJÍ{/Ec‹ú¤eAk‘U‰•P´V¨†¿ÿû¿‡}ÒXD[ )õóõs«‚Ö$Ô‡~«pŠ„"К.|ðA;kÓG}Æ"ÊJëׯ‡AºDP»‹Œ ZŸ,ê7 –2¡8hýPµëÄ"ÊJ(À”¦íSƘ E }RƒÖ%VjОÍ/¸N Ú3•1èË‚ö*#ú;X Ð^©ŒÁÔ'ÖI'÷©jlЩŒÁÔ'+ÁRöJe úÄbý+Oc*V¯^ ÷Ke Z—XÆØTM(ilЩ<ñÄí®Õˆv (ÈTÆBó>”ùË8ê'P ´v*cÑÊÄ2VA“PJ0rnÐz)EkËJ™„ ­M†‚ÖHi¬;0ÄKÑ(ØÔj¨#¡$h/Rš—Ú˜´>±Œ.šH( Ú›tƦö“Ÿü¤Ý=qÓt º%hŒ±®„’ XHê¯ÃØÄ_q ¼.9¼½©„’𘌄l¯Ó$Yõ¿þë¿àê´- Ø‹,3§ÈTD[yÙõŸ¶æ@‡hÂ\A±ú,;Ï¥ùZyývèT^É$”ë÷Œ£Ãø”üÁüÁ¨}×]wbÓ ˜4ÌômÞâ’%Kì sðßÑ#ÁJ¯ ŠËÙn»íàÁ|ÐãXn¸á†ÃuS‚ö-+AQ¿ls¹jÕªáxB&·,Á3‹Š+AôI ¾”†°nÝ:¸FJ ùX£%2õ mBq%è EjæhÆ´A“ ¡g)3~ÄÌ L ŸZÔ#QâhüË+Ž´+Ì\ÆW^y%êzMjøÁ~ûb¸Ùf› ÷ P„¨Á9ŠÿÎaJ~ðP Ûl³ ìCP{.¾ýíoÃ>ò¡‡‚í>%(Q´r\ë=E¿Äšƒ’Çç÷u•=ÇK/½÷)’@}ÈüãAãSJ„ô²Ý§%ŠVÚË(™l€&r9(|J6ÝtS¸Oõ‘¾~®f¬á ƒ‚}$õÉ6én»íÛ5^{íµÃ=ˆ™o} &‹FÚ‹\¾|¹5ÏølZ„ËA äS²xñb¸OY ¨Ý¥o<õÓÇ"ùõÅò™gž®ËAÉ¢‘ƒö"QBã«8@‹r9(|"Ð>!rP¿Ô7ŽàÏy¿Ôðè£ÂvBö•’E#íE%#s€6árPùD }ÊøÜsÏ®WÔgtÆ’¾þ*JP¢hå ½HMBî+mÊå Òˆ@{Åòàƒ†íÆ¢½‹úb‹@‰¢•ƒö#CŠÀÑ*AAp9(y4º@ûuÍ}öÙÇžv”$!rоd™„"*%‚ârPòh½çé{ì*“ }Û¨ ” ¡rÐÞd•„"¢$‚ärPâ„êÅ“E Ä(+ÅAÆH("jb(h.%LYµ|ÿû߇q¥½ à%E9(62fBI‹@‡àrP¢„Ø%P’„ÈA÷N¦H("ibèP\Jš"» Jš"9èžÉ” EÔ’X:$—ƒ’ˆ;M $ârн’u$QkbèÐ\Î4'”¤ E4’Xºntod Edñê¡K!{Ü û26™PDV¯¿œ=9%Ñ¿‚=Iè«' }bõ$¡O¬ž$ô‰Õ“„>±z’Ubõo5”#·· Ù¼Š”T}r…Áï¬KÀ/‡ÛS º³\’«ñW]·ƒîŠœúOé KáöƒîŒl:¹{õÐep9‡üíÚG=³liÌîŽl2¹I,t \ŽI*rê1IE2Ð’M%W퉅Ïåð¤šúäâIÕ‚äª5±Ð¡¹”TäÔ’Šd ;%ëN®Ú –ËAÉ$P2IènÉ:“«–ÄB‡ärP¹ì<(‰\2Гu%WòÄB‡ãrPòøì,(y|2Ð]“u$WÒÄB‡ârPÒhí(i´2Г©“+Yb¡Ãp9(YBÅÌÌÌìÂ… aÌÒ=÷ÜÓΊJ–P(n2er%I,t.%IYCøð‡? c‹å™gžiw %IY(>2UrEO,<—ƒ’£ŒëÖ¯·+º9à€`eä þÎ;ï¼ÑcƒSÅ Ö\†G#íE†$ˆp´ —ƒ’ƧdíÚµpŸ²P{JëØ‚G#íEj“Ë›Xhq.%OɆn÷©¢µ§´®=Ï>ûìá^c ÄÑÈ@{‘šä*L,´(—ƒ’Ƨí¡µh>aÓ/)7œp cch>­d@}RÂ|’õk%ŽFÚ‡ô%ˆh´—ƒ’Ƨí¢o ê©vB>.ë(q42Ð>dQrhü‡ã ¤ñ)A{„J >cQ_lµ{Éq;î¸ãD[¨ ÄÑÈ@û®äšˆMærPÒø” =ÊZ´Úe[U5k^ûÚ×N´›¸d{ˆc¬:'ŽFÚ‡DÉ5ÅÒ¥KáD’ƒ’Ƨíá³h^QŸ‘ú9ëÖ­›WÅã?~¸.ê#W­Z5c8õÔSÇúÞªIØ1PÒhe ½HÉD‹+¹8(i|~ô¤kìì9öÚk/¸Oâ ƒ‚}²K<þøã°¿. ü±áöÛoúK¿OúØ#PÒhe ½°U&%F _¿Œ„lãÏs”àmTåî¾ûî±öªN€’F+£p‹³‡’‹ƒF£„VEÂõùd»+æÈ#„óbj@íäè#%Ë@‚Ë I. :`¨ê‹a кe]²dIáš?üpa¿Ë1fÖá$’– Ôú’‹ƒWVõ•1%h¿P]ë¨Oã(‘¸%)}»®äâÄþt‰‘¾&õi­´¿V4Ÿí!N€ÊXJ·Œ’‹ƒå’ƒúcØ$(ÄÊ•+í£8÷3Fä¤2T¾mž\œo¼iØxãGŸ~úé‰1UÌ ŸÏ|àù[mµì/ã“ÊåÖ)¹8è0HÃ9çœ3ÑÆŸW1GPœM8FĤ2$»yt$‹c|n½õÖvfž ˜«ÈAýÈ1ÖþÂ>ˆC’ÄB‡@¢±†‹.ºh¢?÷IŸÉ?ú£?‚ñ‡JÈÇS‘det$!ÛøóPÛÀqÇgÍÎ~æ3ŸçÑ Ÿ|ðÁcm.S}e¼Oê×ú‹_Œ—ócŽ9fؾï¾ûÚ–æáñ[n¹åX»Oƒ|~úé§O´ñç.'>A‰ñW5(xüg6 ~ùcŽrH.I >—rüµ×^;Ñ&Ÿ™‚è«¢ÀC$vÙeØï’c’i2¹PÇ"%hŒÖØt6± M'Ú—,wyÓM7ÁöPcmEl‘Ô¯QCSÉ…ö#5 y)½âŠ+ìÎq¨=±ˆ~ðƒcÏó›ßLŒõ©¥îäBûZÐÜ2´_e“h«¡@¥„«µ» ¥®äBë“¡ 5ʨ]+&ÑVCJ‹Æm°Á…ýÒ2¤N.´.Y´NµkÅ$Êj7ß|3 Tj@í¤¯ŸD?WKÙäò} _Z´¦K„ùœ¡—𝉋Eõ“@AJ9GqÄD¿ùÉÂÙŽŒ6¹xR‘ÙÇZWÊAýý×íì“Æ"ÊJ(@—^x¡5ÏßüÍß ?¢ñÒO±b&´G*c1õ‰…ö¨ªIÖ˜ =R‹©O,Ú§¬±“Ê€öIe,úIJ ½BM‘T´W*cÑ'í§5URÐ~©ŒEŸX ´ŸVók*Ð~©ŒEŸX´W¨©’ í•ÊXô‰5íSÖÉ…öIe,¦>±Ð‹>ý3¹Êþ2«²Æ¢u‰eŒZ›$PýE½è×±’ ­ÒXLmb¡uI ï“ÿúK\hÝ”Æ"ÊJïxÇ;`©¬ Z“taú\o)¤L.´f*cm5hJË‚Ö"«"¹ÐZ)ÉT%Z‡ŒAìäBë¤4&­M,ch>“XÉ…æ§6&S‘Xh.™‚Ʌ榔¾=QoœZh™’*É…æ¤66N,4ž¬ƒ²É…Ƨ66­O,##ë$4¹Ð¸:ŒMÔ/¿ürtrP?ÙÚäBýu˜‚è«¢ÀëP¢S'®ä"V¬Xûë0I,£¤¨¯ druÔQ¶'¯{‹A’UQðu)AmMBÉuçwÚ–î%•¡s‰el(þ"¯¿þzØ^ÖT$Yùu¯{´ê!Û::P‘_úÒ—ìÌy¨?.cÓ¼ð 0.M[ˆžT±’«Ò <©H:òÊ+¯´3æáýòy›Å¡õsŸûÜpvÚiÔfàc\m.¿úÕ¯Ç(±ŒU(=%•ñ©ž´#æ@óI˜Çûï¿ÿèqLëí[V êãmErPBqËRj&J(.ç–[n‡óiàS´~, ÞF_.ÍÛŠ” d’–!xJ$é{.ùS;zt@êKåŸþéxì>^ÿú×ÃuRIðç¼ß'%‘ËP‚f $r)A‡ô©™§Ó9¨Ÿ|ÃÞ`G…]‚¨ÈÔ£Qòøä ƒI >’@}m“@}.ï¸ãØŽ¤ßM ÄѨE5%F :°KÍx͘6hpýëXrf6Ù&V ªQ(i´JСËhxõ«_ ûÚ¦µÇR‚’E«–‘«W¯¶òJ.õµÑ”g‘ dÑÊAksœ½XŒäŠñÞIŸÿC}.CÇ×­/>_¿Ë¢OÛ„Êá{¸€=|¢1FrIäZC稯NÍoW»O J´)™hA“È6&—vœñ˜cŽí!Ûn»-ì;á„&ÚIçS‚F#íÕÀÓ ‰d›’˰lÙ2Ø'%PI >R‚úe›ôðÇí%(a4rÐ>\n€ «&×ÿ±=Ú§ª!ë|/(±Í6ÛÀ~Ò@ ¨/…”09h® wÏ´Y5¹.¸í|;{´OY Ô‡ÔŒ¥1ôÑ%ïßtÓM‡ÏéÛ» O<ñĨ?–”09hnŽЂdÕäúñCÿÏΞíSÆÐµ|ã _ùÊWFe?—pµÑÇXJPÂhä }¸>ü# …ɪÉõõ_|ÍΞí*ú¾±²_>—¢~Žì+«%ŒFÚ‡«A7jÚ€¬š\|Ñb;{ž·¼å-p¯¯»î:»ÚììsÏ=Ç—,Y2ƒúŒ_øÂ&úåsiQQŸÖ»ï¾{¸%ŒFÚ‹«E?rÚˆ¬š\FÚ«ŒEk¨ÏXo|à û«ˆ@ £‘ƒöâ†6zÚÌ=¹\úöpõ»ÚI_(a4rÐ^ÜPÂg @“©’«èeU}ðÁa»‘@}ëׯwöÅ’E+íÇ-C¹YPdŒäºý‰Ûì ã ýº.%‹VÚ[–ò3 @ÈÉetö욈™›n‚É¢•ƒöäV¡Úì( 2urоm×J”9h_nUª¯0FÆJ.chï¶ébfÁ˜(!rÐÞÜÄYe Œ™\Æ"Ðþ¹ëdð ”$¡rÐþÜXÄ[i ”Œ\gþì »æ}ï{Œ#¿õ­oÙH/¼¤Œ7&qW€&c'—ñ‹?™{W¼ˆE‹Áxêö”SN±af–/‡ÉQVЇ›ø+@“)’‹Ô‚âJ¥–™¥Kar”•ƒâ⦠ͪÐÈÉU•ã?ƪõôÓO·+•'VrqP¬ÜT¤[y:3¹ºDÕäâ {ç¦$íêÐÈÉÕEÊ&Ý775éw€FVI®.š\tÏÜ:¨g—è€d™äš´ÉÅA÷Ë­‹úv€J†$×4áK.ºWnÔ»Ût`R“\Óˆ+¹8è>¹uSÿŽÐÁÉ¢äšfdrqÐ=r› ™]  QrõÌ'Ý·)šÛyº’'WÝ·IšÝ}º²O.7辸MÓ|ÐÅ{Ü,üoÝ™1²yõr¼œÜAÉ• Y½‚¹]NàÉ•ý«ØLråFŸX=Iè«' }bõ$¡O¬žžžÖЬžžžÖЬžžžÖÐ,ýç—zêÂ|údùòåöY¢ÿÓè€>©ËíéIú •¾paú?…™8Èžž B%í ×8ýŸ> JŸ==eÐ*i_¸æ˜ú?u(9´ÎÌÌØUzzô \Ò:í…kj J­}¡ê‰Ê-­ÓZ¸¦®`¡_««Pò·ÿ9fOÏß|lvö-çu€rMë´®©)XèÅÖª-TÒž)E*©”{Z§¥pu¾`¡WkÙB%í™|…Jêå¢Ö®®Î,ôbjU¨¤=%´PI ÜÔÚÕÂÕ¹‚…^<­© •´§#T-TR(Wµv­pu¦`¡Kk]…JÚÓRb*©”»Z»R¸Z_°Ð‹£µ©B%íi © •ÔÊe­m/\­-XèÅКK¡’ödJÝ…Jêå¶Ö¶®Ö,tùZs-TÒ&¸ôÒKá5é[l1{×]wÙ éB%u€îNkÛ Wk ºl­m)TäÿýùJa6Ø`x/]qÏ=÷´'Dn…JêÝÖ¶®ì º\­m)T®8C@çï}ÕìvÛmgo¨$l5Y0rѺ­¹®l ºL­¹ª*¼å-ogî óÿñíòÈ"\<šÔ:·Ö\ Wv ]žÖ\ Õ/ý´$Œƒ:ž³7W^y¥½ùPiJè¬Zs+\Ù,tYZs,Te@gëmÎ ØWFÉÚ;q!©[èŒZs)\,t9Zs+T¡ 3õæëæ›on_9%¨˜Ô©t6­M®Æ º ­9ª>ûÙÏÂóô¶ÓU«VÙWV*(uéIkS…«ö‚…¯5—B:Go÷üßùûŠ+@E¥ óh­»pÕV°ÐaµæP¨NûןÚ]ý 3ô–ó€€í9k¾îMÅGàÂ’Zè,Zë*\É :œÖ •NÊ÷_И-â™gžsrr‡v°Ñz@…%µÐ9´¦.\É :ŒÖ¦ Õ¡ŸºÂîXÌ‘G ãoÒ½÷ÞÛF‡AsÚ¦4¯iW¯^m£+àá=qqI©t­© Wô‚…‚×Út¡ºæ'¿¶;ƒboZÎË/¿ ÇtEõµE?ƒ? ¨¸¤ÔŠ_kì­`¡`µ6]¨V?ÿ²ÝÑÍ'?ùI{.rPWä þ¶ùÊ+¯ØÓ€ŠKJ øµÆ*\•  NkÓ…JŠ;W‰Ÿüä'°ßÈÿYò£ýŽÉYõ••ƒúëðo|£ T\Rêůµjá*]°P0Z›.TO?÷¢ÝÑ Š»ßô¦7ÙÊÅ@¸îØðîw¿ÎÍ]býúõ°?ÔÅ‹Ûgg_ýêWÛGó 9uè—”:@±k-[¸‚ Ú\kÓ…ê‚Ëï´;ºAq×-aÞ@GýErÌO*@cÚ(ÿlêÕ¼ÏG ~ “Z/¨¸¤ÔŠ]kháR,´™Ö¦ •ÑŠ»)}ôQU¹¸ˆ³Î: ö·QÂ|ƒ2ꑃú¥ÄE]ûS[ÈÌà_ ¨¸¤ÔŠ]«¶pyn£Z}¡*/ú4¨ïOþäOlï8hlžzê©6Âê1JÐé{ìaG7{G…<´#..)u€b×ê+\Þ‚µtéR¸p‘9ªÇž\cwÅ ¸Søâ‹ãï—¡1Hê÷écÍš5p^—%Ìœ†¼gEÜ{ï½°¿N—-[f£q€ Kj ø}úð°h W…ÊXÄwÞ cOíÖ[om#˜ã¨O£áž{î}Ó$¿{ó^ãÍiÒBšøg¢ÑŠ_ªE?Ò‚ W •AÆÝ”Ûo¿½h4Žxç;ß û{ý|ðÁöÃþà˜÷Qn‚ŠJ:Ž>Ãb W.…ÊX„ù>:tY9¸ãŽ;Ú(ç0wJ}ùÈGlk>ŶëwÜqöÆ«ÝùÂ… í*³³ßýîwá˜XÞ~ûív'ÀúçqQ©C&æ²”Ÿ @…$µ§ž‹Ý#_ÜœÝ}÷ÝmÔs<ûì³öQ_°ê’8äC`¿Ï«®ºÊ®0“ÊBPA©ËˆD+X§ýëÏ`AIiïz×»à‹Kê¯êïÿþïÛÕÇÿÖÕ›NâÓŸþ4ì/R‚ÆÔáºuël€·Ç¥#­`u®"Ð ™JN×ÿ_卵œ¾é¼TPR™è‹HY¸Š@/^r-ZÇôvLJ~ؾڳÃ_†Æ4m!¨¸Ä4É ³p}äóרU'ùÆ7¾_´ºåäøëßCÜm·ÝìIÒcþ)ƒbÈUõi¼à‚ ì s 11,šª&&yÁ"ª®ï\·Â®4 z¡š–óüóÏÃ1¹ØPÜMÉ¿® õ)?³ŽÆÄö›ßü¦Ý €ŠNk¢öl-S¸V<ðŒ= zrR‚ÆÔi—@ç«KâòË/‡ýRN¬Ÿ6âf›mfw ¤µfË`mázðQ÷¯RB/L,;ì°Ù~ðƒ°¯Œÿðÿ0ü™G¨/¥Ó:J9æëé|cÎ;ï<8¦N bTdC4žÑE…ë†_Ì¿±)A/FU} 9¹iþPôÌÎnµÕVð~Rxÿý÷Û]1hN“:A…IÚ0,B®“ϾÑöL‚^„*ÞrËüŸ¢þm¶ÙÆöæY´øO3è™d£6‚÷6Í:AEʘ Ù,‚ — tùUä ~Òš“ÚžpÐ=N«N2,TD«²]z9¨Ÿä?"æ”SNëÛo¿ýlϼ/…òÓá=å0?^ÝoÓqÎ9çÀ9eÝu×]íÊí¡5kà 7„—^VÎé§ŸÇ9¨¿.]ßhÞS2߆“Jâío»³Ï ûªè{ÿ-7ZQ°î¾ûnxÙ1D >>§N×®]k#pcÆí»ï¾öYÄÜ ¿Sóe’÷¾÷½ccRH >#úŒæG4¨¿¬m¢Ñ¢KNá1Çcwœçú믇cS{ÐAÙ0®7’ûÂ5,TÒû·³#çAãbI >#õ‰O|â°¿¬m!ûHÑå֥䩧ž‚ãb[„öWtMsáò*)«*a~ ê7¨$P_Û@ÖQ¾æ5¯Û„üИªòŸ…@s|NSá -T¤ëŽvÞyg8¾ŠzŸŠ÷/Y²ö§ô¥—^²»çKÖ ]jWÕûeH}'hn9¼ÝüÆn‚·×iîd!ºÌ®Z†¾pÕ{hªº@cë4g²ŒÎ|f ]d×<ꨣì‰Ë3…«©3£5»hÎdºÄªj©ëVÜpà vÇ8LCáÊáŒhý¦¥oC}eÍ•ì"3_UŽ.°¬ÔÏå\sÍ5pL ¿÷½ïÙ]âÓÅ•ۙÐ^MúñÜF/¶\É.2tye%P_‘Ô_Å}öÙÇ®œ–.®œÏ€ömRõ•5G:[°ˆO<öû$P_릅«-1£šòÉ'Ÿ´QÅÿ3”YE….­¬êÓH ¾²6I]Eàä“OÍ5ChK¡â xRxøá‡Ûý ùe¼ï¾ûìŠùÐÉ‚Eœ{î¹°_#úʘ ©Š/TR_ájc¡"\_ZF wÝuœk$bþBÜÈ*"tae<øàƒíŠÅ}ôÑp>±bÅ Ø_ÆÜˆU$Š •T®6*б) ÔWÆÜÈ&"ó™ta)<óÌ3í®Å ¹eÌ™²EcáÂ…°]cÙ¹¹*â’K.ñ6!úʘÙD„.«)=öXØ^Ö6P¶pÕa®…Šƒâî‚ûï¿¿=aô+±W_}µ=a;È©pµ¡P(þ®˜}ÁJl[i²pµ©PqÐYº`Nô+±m%äÍôØú>«˜+è,]0'ú‚•ضÑd¡’¶­p¡3tÁœè VbÛBN…JÚ–Â…bï‚9Ñ¬ÄæNÎ…Jš{áB1wÁœè VbÛÀI'cÏÉ6ü- ÅÝs¢/X‰m9®¶üsЀâï‚9ѬĶ‘ W› ÎÑs¢/X‰m3U¾ý¦¬f϶‚ÎÓs¢/X‰m#9|µ{Û¾xtÑ¢Eð]0'ú‚Uƒm!‡B%mKáB±wÅœÈ&š7Þ^VÌ •4÷Â…bî‚ëׯ·'̃¬þ4¡ ë‚ ,°'Ì‹²…ŠŠG™¯á¢7Ó«î(ή˜}ÁªÉœˆ],4…ËõY¿.._W̾`ÕhÓ¤.¨p¹ •¤­… ÅÔ<òH{Ê|È®„¢‹ëŠŸøÄ'ì)ë¥îb`Š”¶PIÚT¸P]2Gú‚U³uÒ¦?ü’ÜcÿÔ§>÷ï’9’]T‡z(¼¼.™š6*IŽgy饗àž]2W²Œ ]`×LA— •$§³¡}ºf®dÙâÅ‹á%vÍXt¹PIš<ë³Ï> ×îš9“mtè"»h¦©PIê>û{ßû^¸^Í™l£{ôÑGáevÑ7¼á öÔ:¦¹PIê¸ 4¿«æNÖ¢ í²>úBå&ÕÝ 9]õ·~ë·ì©ó%û’Š.¶Ëþüç?·'ŸÄ|_šãr •¤LáÚa‡ììy6ÝtS8¶Ë¶ì£|ì±ÇàåvÝ"Ðxî4*‰¶p=õÔSvÆðØó qÓàw¿û]{ùÓšÒŠ.zšì©†)\m´‘}6ºïi²M´*ZtÙÓfO<ÐýÆ”ƒús°m´.btéÓhO9B?qQVâ¶Ûnƒý9èäå—ggŠú$«¨–]ÿéÙ=/Øchèò›öÆo´Ñ̓ÆÅv‹-¶°»õî.…ÔŸ‹E˜bÅ͉,¢á…Š[zRûòàÿzöâ‹/žýå/9û / ïÄð[o½uöüóÏŸ=ì°ÃàܶxÅW ÏdøÎw¾Çø|òÉ'í s˜6ŽÕ+WÚÕ'™9ñDXtb˜’$«§(TÜuë_±;aЋ[b÷Ýw‡ýZ9¨¿·~/¿ürûŠÌsÄGÀ±eä¼ímoƒcªZ*2)LAÔUS*îA—¿‰Œ^Än¾ùæv‡j{ì¹çžv•ÙÙ{é­×Ë.»Ì¾"³Ã¿)¢1m°TXR“h«¡¢R‡E¼ãï€/hÓrPoýš÷—Ôß_y¥ø_¨˜Ôe,â–¿¨¨¤Özq›z{Z~>x[$P_,ºŒM©—.]:º¨Õ«WÛÖqPaImæÇ‰ð¸n9¨¿·Y Ô—³®/¡ P©C<ö2Íâ…JšKáòbOé‚ ìγ³ëÖ­ƒcbH ¾i“ÿ¨_Ôä ~ŸæoÌêOa3[l Ij] øÉT£‹ •´/\ãW]uì!ñÃþöO£Ä¢E‹`?’ƒú]rPl} B’Z(~— G…*i…ËÇ¥—^ c­)+õwÁsÏ=מPÆ7¾ñvFø½p|_ìI 1±õ Ij] øµá¿…hQ­m(\ .„±§P‚Æhå þ²î¿ÿþvÕ¸ë–á*$\ê÷yÇwØÙ˜M6Ù΋íŠ+쎘™½÷†Å$¥.PüZ—/_nWqãÞ€6Ñچµá†ÂØSȿˀÆyÉ%—Ø™Õ^$õk• 1wÞyg»ÂÜïÿûí³9о¡˜¸òÊ+aÎzÿ?û,,&)uâת)TDPÁ"ЦZ›.\Ç]ãÿ™Q¯ýëaì9I ¾ª¨O+ñÒK/ÙGs ±9¼}íÚµ¶uÞG¨/G‹~ÕŠIJ] øµ†*‰„Ö¦ ×u¿þÝÑÍ×¾ö5{Óûì³ì¯â5×\cW/ÿúò/`¤6"ázïQBí(žÕ€ŠIJ] øµ–)T„î–<  ´6]¸¾ÿ««ìŽÅ Ø›Hõ%„ù‘Ϩ_#áj7È>­êãrøW±kÞûª[ ¨˜¤ÔŠ_k•BEènK RkÓ…ë/¯<ÒîX нn]ì´ÓNp|ˆêÓHÈß™(û ¨ß'ÿBIÔ/]²d‰=W·[mµ•¦€»î‚Å$¥.дÆ(T„;   µ¶áÍyƒyoÅß”4®Hê÷Y´ŽO"Ç¿-ùÔ0³í¶°˜¤Ô:ƒÖ˜…Š(—eJÐ!´¶¥pÌWV£3´Mâ=ïyì/’ÿÍ糟ýì졇:»ÝvÛÁ±FbÍš5°ß'úrÓü¬0 ¨¤Ö:‡Ö…ŠHZ°t(­9®ÓoùªÝÕ:C[$PŸOõ¹$n¾ùfØßfwÙe{ºbf¾ô%XHRëEkÊBEÔR°tH­9.cè]”X¼x1ì/ÒÐÆÚ!ßþö·Ï£‘:tΣµŽBEÔZ°th­¹.cõWÏÓÛnŸxâ û ûA¤.] 3i­³P,]‚Öœ ×_´Øî®©·†€ŠGº@çÒÚD¡"-Xº­9.ã^üž t¶Þ< ŽºuΧµÉBEdQ°tIZs+\dYÐ{Ó»ÑFÙW@ÏÌç>‹Fº@gÕšC¡"²*Xº4­¹.ã1Wm£ çÅ_„çí­f)9†ŠE“º@gÖšS¡"²,XºD­9.ò¼[¿a£*Ï–[n Ïß;î‘G꾓òÌ3°Hä  tZs,TDÖ‹@—ªµ …‹ü_ßz—®:æ—š¢ûèº1˜ÙuWXrÒº­9*¢‹@—¬µM…ËX‡~8¼«\ý§ú'yzf–.……¢i] ûÒÚ†BE´ª`èÒµæ^¸Ú„ùò§œrÊì_üÅ_  á6Ûl3»é¦›ïÙ|4?Éu¿ýö›=ꨣfÿùŸÿyö–[n±3ÛC.…Ë…ÌïÛT¨ˆV,½Zs+\=yÓTárrZk Ñê‚E EkÓ…«§]ÔU¸\ ÖÚæBEt¢`èEÒZwáêi7© — ”³Z»P¨ˆN,½hZS®žn«p¹@9ªµK…ŠèdÁ"Ћ¨5váêé6e — ”“Z»X¨ˆN,½¨Z«®žéB[¸\ ÔÚåBELEÁ"Ћ¬5´põL7®ÂååœÖi(TÄT,½èZ}…«§‡C…ËÊ1­ÓT¨ˆ©,XJ­®ÂÕÓ£å”Öi,TÄT,%…Öžž–þÆ…òHã4*¢ÿÇ@Iâ²§§ !…«/Tóôò(iÈžž˜®¾PMÒÿ ,€'OOOJxáê •›þObOOOkè VOOOkè VOOOkè VOOOK˜ýÿùë_¦Óy¼IEND®B`‚PK!¯r$word/settings.xml´W[s›8~ß™ýž×1˜‰Óáb¶é$ÛNþd[@Œí¤¿~·ØNÎv²íô 8ŸÎý“t¸þðT“WÕ°®Lc«Læ¢Ú.ŒoéÔ7&fUÎ Yñ…ñÌãÃÍŸ\ƒ†k Ëš ˜¨š ÌÆNë:˜ÍšlÇKÖ\ÉšWn¤*™†Oµ•L=îëi&Ëši±…ÐÏ3bšÔÌÈ…±WU0˜˜–"S²‘ݪr³£†zß^%‘Ù¾ä•î<Î/ Y5;Q7£µòg­¸~”Ä¡,ÆuGË|GºG©ò÷„×*ÔJf¼i Ae1(ª“cç¡ßWà{H±3ê–Ù½Gîþ?䕦xO&=t'ÖŠ©ž'CeÜn+©ØºVB:ˆÈ¸Z~—²œƒš« zœ6McÖŠ—òÀ¿×eÅŠÛª÷ý?C¦yXå¢äª(7+ R0ÙÔ¼(º‘œAÇ`«X ”%NÎ7l_è¶^iYâƒ\=2„‘í˜b™æjU³ ¬Å²ÒJãº\þ#u ÛCA÷z]®V;Vó¤7ÜÜ\Ë iƒ§frø¤Ês¡a»Ö"/ÙÓ ¦3o-Ì0Ç`#¥®¤æ_ÔùÄ!ò…1µz߯Ä]³×º¼Êß|¼²s)Í\(ögÂémÕŸ/ R±š|qfÜËœ· Ø+ñ~¶ ]‘*}/PGÀ¥DÎZr­ôsÁSèÑJ|o©ñißh;æüB? €W­çϰžkžr¦÷À†ßä¬#\Zˆú^(%Õm•öùmÎÄfÃ8°¥î‰BÉcWçœå°5ÑïìœFp©åÓÛ—¯ÀØq©i:! Óp8=!¦KÍ‘¯¹çù †X>M<ERÛt| !ž—˜¨59K Ä^ä§Ù%’x4*‰Øs7±»cà º®¡HbÆ Z{I옢HêùKÔšczéÀ™“¥ƒÖí¿ûㄞÚ(’Ð%Áu–Vê¢ù¸…j£¥nä¡HH#­µ›˜~ˆfê&Ċк¹©g¹((¡©‰r‡ÚÄÑ|¨KíõMb£ùPß )ABE3õצ(½Ðã¬òb+NQÄ'µQk>ô-A»íß’Cæ1]Zh>¡C¨‹ê„¾9(w"“øª9Îï\”º^L0$†JPÆÇ–E(wâ¹gãÝŽSâQ'YZhÝbÛ.[âSjâÖb“â»diÁöF9ºL‰9G¹“RÓÁY•z°UÑ]’.©×wnÖCp®—A;r·³CÿÖ^Ò“²×ˆY¹V‚MîÛ¡|Ö®X«ÇHT#¾æ0ýñsdµ_àtÚMÉŠ"…am:Š–A.š©î½¸gj{²;¬P¨ƵO/¶Úᔫ¿•Ü×=zT¬î/ßq‰å8ƒ¦¨ô(Gy³_¯F­ æâ3h_埪«Ó©<Ç@Ã%Ú 1w¬»Œ»µ¼š~[õÅÎ µj/Z~Ï꺿¯×[kab»ÓV{ÅjøÊáß­ûXoÉ€‘#=Ö}°¬Í V/'egëìQfŸdÎ(sN2w”¹'e´•í`RR0?Âè0¾¶ò, yäùÇþFÔ¡©vÆVìYîõÅÚk×—r¦Ù8´\(wKûS‘  ãê¹\Ÿþ®úÀ ÑÀ UÃo…–jÄþê0Ëíþ7ô°øû•o"Öð¼ßHãüÍ¿ÿÿPK![mý“ ñword/webSettings.xml”ÑÁJ1à»à;,¹·ÙYº-ˆT¼ˆ >@šÎ¶ÁL&̤®õék­H/õ–I23ü“Ù;Æê X¥ÖŒ†µ© yZ†´jÍËó|pm*).-]¤­Ù‚˜ÙôülÒ7=,ž ý)•*Iô­Y—’ků )CÒÇŽ]Ñ’W¿nòÀfWÂ"ÄP¶v\×WfÏð) u]ðpK~ƒÊ®ß2D)É:dùÑúS´žx™™<ˆè>¿=t!˜ÑÅ„Á3 ue¨Ëì'ÚQÚ>ªw'Œ¿Àåÿ€ñ@ßܯ±[D@'©3SÍ€r >`N|ÃÔ °ýºv1Rÿøp§…ýÔôÿÿPK!ZÖCL@ ž~word/styles.xmlì[sÛºÇß;ÓïÀÑSûØò5ÉçŒíĵçĉO䜟¾¸‘µÅQO§Ó¼Ä"µ?€Øý/°$EþòëÏUý yÁxv6™¾ÞŸD4‹y²‡³É·û«Wo&QQ’,!)ÏèÙ䙓_ßÿõ/¿<½+Ê甑dÅ»U|6Y–åúÝÞ^/銯ùšfbç‚ç+RŠùÃÞŠäÕúUÌWkR²9KYù¼w°¿21˜|…/,¦x\­hV*û½œ¦‚ȳbÉÖEM{B{ây²ÎyL‹Bô*Õ¼aYƒ™ЊÅ9/ø¢|-ÆôH¡„ùt_ýµJ7€cà ¬âw7ÏÉ<£/z Øä½þ„Çè‚TiYÈù]n>šOê¿+ž•EôôŽ1c÷¢eY1Á»>Ï 6{()Êó‚‘ÎKùG瞸(­Í,a“=Ùbñ§Øùƒ¤g“ƒƒzË¥ìAk[J²‡zÍ^}›Ù=±6Í÷lBòW³si¸gLÿoîzû“jxMb¦Ú!‹’ŠÈšžìKhÊd ¿­?|­äØ’ªä¦Ðÿ7Ø=0â"àDøÍ´ Ä^ºøÄãGšÌJ±ãl¢Ú¿ÝÜåŒç"ÒÏ&oU›b㌮Ø5KšY_Ì–,¡ß—4ûVÐd³ý÷+­fCÌ«Lü}x:UQÉÇŸ1]ËØ{3"}òY¤òÛÛ4®ÌÿUæÆ]öKJdˆ¦ÛÕ}â@ZÖÑv3«­cWßB5tøR ½TCÇ/ÕÐÉK5túR ½y©†æ?ÙËúS 6¨»85¢9±¡9-¡9© 9% 9Ž@GsqŒæ8ÂÁ)yìŠB+ØÑÞÏÝ=GøqwO ~ÜÝ3€wwÂ÷ãîÎï~ÜÝéÜ»;{ûqw'k±büXIHtQ¥) Äú&Äk|m 0ãK…_(ÌøÂÀòY¨!2´@#ehÌЛŽÏPãfhÆÍЛ¡·{V¦*Åûº»L¹<=º3ö1ÿŸmÌ)ÓèŽää!'ëe$OJwc­CF·sÁ“çè>Ä”ÖB-ëU„\Š£fY5~@[´PÚjxÔÕðé«áWØ­X%ËõÙu˜rfVÍË.ÍNihg$­ôzv¼ÚH9>Â6¸byLÝØüY®f¥;Cd¾M/ÇwlÃ/«í¬´{ —)äáëç5ÍEUö8štÅÓ”?Ñ$qVæ\Çš-ùå’A’ÿ¸Z/IÁT©ÔB Ÿêë àÑ-Y> »”°,Œß>¾Z–FáV×÷·Ÿ¢{¾–U¦˜0À ^–|ŒiNþí;ÿ=LÏE œ=:Úó@g‡ì’˜d4‰'Hb™É2dU¼ßèóœ“< C»Ë©¾ç¤¤ˆ3²ZëEGm‰¼ø$òO€ÕâýAr&O …Õ}˜uÖ°¨æÿ¤ñøT÷™GAN }©JuúQ-u•u8ÜøeB 7~‰ ¼)¦¿¶…°-\¨ƒ½LIQ0çTo^¨Ã­y¡w|ñgx<åù¢Jà ` 6‚50Øò´ZeEÈ#V¼€¬x¡7`È(^€3rŠ÷œ%Áœ¡`¡<¡`¡Ü `¡| `A0þ 6þ. 6þV ´°`¡â,èôè" g *Î,Tœ)X¨8;üÑÅB,‚ÃM12TÌYÈpMVÒÕšç$„ü˜Ò੦Ýå|!ŒÀ3}w¤=| ùcg œöÅOSã9‚ï´/ŠãÎfû©±ì ÁÓ¾(jI%:cyµzg˜fÜöÃÄã¶Ç¨ÈMÁÈÉM¬+7¢O`_é&gvLÒTí5wO€¼¯у2çï×çí[œ†ÿ¦ëF,œ²‚FœÃá®ZYÆ=ŽƒÓ18︃1(9ÍQ)ÉMœ›ÜˆÁIÊ@g+8#಴Çe+hï“­ Å'[X¸ƒ—nZ¨ꈕ‚*0÷*¤ … h¡BZ¨p†*´Ç ÚûR|„ )h¡BZ¨*D … h¡z®íæ^B…´P!-Tˆ@ U­GÚã„ í}„ )>B…´P!-Tˆ@ "ÐB…´P!%T`î%THA "ÐB…´Põ/ ý… íqB…ö>B…¡B Z¨*D … h¡BZ¨*0÷*¤ … h¡BZ¨êbá¡B{œP¡½P!ÅG¨‚*D … h¡BZ¨*D „ ̽„ )h¡BZ¨ÑŸæ¥ë6û)þ¬§óŽýá—®L§¾Ú¿ä¶Q‡ÃQu¯Ü¬á¿E¸àü1êüÝᡪ7†AØ8N'Íý¥€ÐŽáÔMè Kè«:Ca uš›0Ô{nÂP7º (:1xǺQh»Q~®†2úÚ_¨nÖÕàåj€ñw5Dy»¢ü\ #ÖÕ€uµrv¼\ 0þ®†(oWC”Ÿ«áT†u5$`] XWœWC”·«!ÊÏÕpq‡u5$`] XWC‚—«ÆßÕåíjˆòs5¨’Ñ®†¬«!ëjHðr5Àø»¢¼] Q}®VgQZ®FyØ2Ç-Â,CÜ„lâ’³eèQ-YÖžÕ’E𬖠¯jŸãª%ÛinÂPï¹ CÝè& üéÄàëF¡=ìFù¹W-u¹Ú_¨nÖÕ¸jÉéj\µÔëj\µÔëj\µäv5®Zêr5®Zêrµrv¼\«–z]«–z]«–Ü®ÆUK]®ÆUK]®ÆUK]®9!;1þ®ÆUK½®ÆUKnW㪥.W㪥.W㪥.Wãª%§«qÕR¯«qÕR¯«qÕ’ÛÕ¸j©ËÕ¸j©ËÕ¸j©ËÕ¸jÉéj\µÔëj\µÔëjGµ´÷Ôzÿ’d«÷‘‰/—Ïk*Ámý`&ÑÏ 5Õo’æ=IÒXö$2o¤2›U‡ÍCÝ¢2„MÅKÑVlžžähÊ<µùzêvÃŽG¥ªŽl† þ¶ÒÍ¥Pý½ÖeÏÞ~—rÈ{ú¬\Ò;FÚk®¾5a¸«‡¢?óT¿³Küq“%ðdz«{šü$%ö_Ò4½%úÛ|íþjJ¥Þ;ÝW?šßÚ?×ÏsÚç*Q8{íÎèæ½aŽñÖ„7W°!)ÕÐ1Üêvб#íî[K.›P7lwFoÕƒHø‹”2PN&Ÿ+Ù±]>±Eºò1C^0é{µkÿàâèãô\ï1¯t{¤týYpÕ6ùáËh¡}ûmoö»ÞNUïz“¯SËäcð+’š&ëQ2íu¾FOt;§ó*^Ò2ºIðæÍuÛ{Ô ôàæ¸ØÚfú"Rßæøå?ãÖæ¥zõ=­—ê©oYïÆ’¦âªѯ’'}ã”NÇGmy¿3Çuû|—¿ÿ§¾É³íÌ*OÂ!VÓ ÚÕ5ÄvJvä‚úA;ÅÔ«˜£æC÷ÛÛ9û‚ç ÍÕ,¬s²jU>ˆÜøŸbÕ¢MÚ¼ÉPŒº­E“±½l›lîe]çz/c&"-¡×ãÌÿð3×ÓN3üCf¡îL/g—ÍoŒ·£R­Ð6»w¥þŽ 4÷!m–SÛzx~|||Ñ P¦V2*äý‚F’} {ÐæÑê)Û‡ÜzlÇ®¶ó›ÝdÊ1‹£ö88˜^˜*%Œ¹vF8¾ÝXÙÔÞ$3ióy+YNMc'K½-Ü,µ=Ì}þ;eÙq‚s§Ûwÿ]£Þ­ó„üí¡5ïÈB“†èa§.öÞœ^¶ &X=÷yý=Y;êZóBÖõoLþ°¾£²~ó•·‡ú¶}™C o”°Æ‡¸5hÛ.Ð»ÆÆµñ︆MWú½oÛ‡b^‡‰&Mú4¡¢É´mè]c£Éøwt4Õïÿ ÿÿPK!ˆMv©#word/fontTable.xmlÌ”ÑnÚ0†ï'í,ß—8!Š*ÊŠTiÛÅJÀ'±Û‘mÈxû8 ´ªXI§VMÉù}üûøÓñ¹¾ù# ´ãÆ ­F\1½*Kðãjy1ÁÈ:ª6´ÐŠ'xÏ-¾™}ýr]MS­œE°^Ù©d Î+§A`YÎ%µ]r“©6’:ø5Y ©ù½-/˜–%ub- áöADÈ·6概ñošm%Wί /ÀQ+›‹ÒvnÕ9n•6›ÒhÆ­…3Ë¢ñ“T¨ƒM¿0’‚muêp˜6#oËCâG²8\ö3ˆ’Mï3¥ ]2A`†g-}TM•0±’[ô“Wè—–Tù€’*my1;Z$˜DðŽÈ\’¾F1ê@–ScymÖ’FN©žS÷õ¥p,ïô5¢N®™²"ƒ‰­]“ßB¢»å7J˜à(ãIèOÇ£Ì†ÌÆR\ËåhA…ÕÍ Ú"ò¥ÔúJí3úVµÿòI»ÿµjùÝ«äÐ"ÍoÇvñ1ó–ݦ#9 ³håâeVâu °ÎjÕ›—Y„Ó„õô1•›£…Ký/ºf}ÔlÜcµ¿À}´þ•üýïy½…&lõ¶ÞxâÂ8»C+3-ïÄìçpéï(tq½GzGÄ_®š]Ò¡qèèû.éÇ.™ Ksäù¡[¼ÇþÜÒû–@„Œš$» BmIgr»dXŽ€Kæ‡%ÅŸt¦qT5ÎJ:ëc’ÎæŽ¥‰”ûã’ÎáwÉ9* g¹ä|XÒõù“Î6JCCÒ© À´´R› ¸)Aëk`Ö/\—” )AR‚pÁ–” )AR‚¤„SºC ¬ºsS‚­‰1ѳñÅ)agSàØÅŠÄ~ ö(¡„yæƒ_Çq{.iܹ¤"¹T7ñ§×C4‘i¦Ó £iæÆAÀjÓ[]dšé6úì,˜¶HYè6"ôÙm€çÑ''°RÈÓ Ô§6Ì0Ö Í4ªGQ¢S `·×¯k®Œ‰5ëkÓkÔ~<8Yaž_ÓÓn“Ä1Ý6Iœ€Ñí“„uš$NàèÆIâŒnŸ$Äà¨Ó$qG×! V;¸IÂ0ƶ­ƒ —4àÇ.´ìâ”$t’hyðµ ñ.ÂI’$!IB’„$ I’$H‚½hÜ$aBûQë ×åy„Aa.Øò›R冎S‚<Âp;ßçËJnJ° iê†nçÆÊ‹k!‚\oøÿHB®7r½á¢¤“ë r½á^o`aä'‰± Mǹ±¢$¡›c @ýœÃôU¹Â«ÑiŠŽeÀ‘•ö +ðòu‰ïÖ ‰%J$JH”øQ‚ù̶=²lk6Ê•[rëBn]l¹uÁ¦T¹u!·..K:¹uÁþ÷ÞºÀàò7Ø­T(Ç× u¸F 6‹e_½hËO8ÖŠeû b'¿@µ3[ÄòýZ1§EÌjË‚Û f7‹•©sšÅ²¥—±jÅŒ}±üš£ÞÃÿÿPK!Ía,)âãdocProps/app.xml ¢( œSÁnÛ0 ½Ø?º7²ÓvhEÅbèa[ÄmÏšL'ÂdIØ Ù×¶OÙzªOôÓI‰Û×ΈÉx·bÕ¬d8íãv+öX¹¸aEBåe½ƒ;Bb·ò㱉>@D© —Vl–œ'½‡N¥¥eZ;…Æ÷mk4ÜyýÒC>/ËO^\ÍE˜Ù¨¸<à{E¯{é©>Ò“¢†.X… ¿÷ÚYã±|bEíQÙÚt K¢§@lÔ’¼|âÙÇ&Éjqy%øˆÅz¯¢ÒH-”UU΂gŒø‚5Z!µW~3:úä[,ÏE¯ x^"è[Ð/Ñà±·’‡â«qäaQ >"rÕ.ª°Or>xœB±ÕÊšz [eþ—÷ úùn”épy>Éü¢ ÏYñC%è;·brÈÆ²1° £¬ ZÒžâæe96W² œÁàð¹»á„ôÐÒÝð ³Unvð0ZÍìäÎNgü£ºö]PŽ:Ì'Dþ™CíïúýøÓÃs2›ü³Áý6(MC©æ‹Ë›|²œØ ušÊDˆ{ºC´ý ô¯ÛAsªù?ÑoÕÓøfeu=+éÖèÄÑ*LIþÿÿPK-!û˜õ ‹_[Content_Types].xmlPK-!‘·ïN Ä_rels/.relsPK-!4öö<Ãäword/_rels/document.xml.relsPK-!íF