2006-07-04 Esteban Sanchez <esteban@steve-o.org>

* windows/pandora_wmi.*, windows/pandora_windows_info.*, windows/wmi/disphelper.*,
          misc/pandora_file.*, ssh/*, ssh/libssh2/*, modules/pandora_module_service.*,
        modules/pandora_module_proc.*: Added to repository

        * pandora_windows_service.cc, pandora_windows_service.h: getXMLHeader renamed to getXmlHeader
        and modified its behavior. Updated to the Pandora XML specification. Add SSH and XML generation
        functionallity.

        * modules/pandora_module_exec.cc: Added the execution to a job to prevent zombies process. Update
        the execution command.

        * modules/pandora_module_factory.cc: Added Pandora_Module_Proc and Pandora_Module_Service. Added
        the interval parameter.

        * modules/pandora_module_list.cc: Added support to Pandora_Module_Proc and Pandora_Module_Service.

        * modules/pandora_module.h: Added new types of modules. Added execution times and module description
        to the Pandora_Module class. Added support to Pandora_Module_Proc and Pandora_Module_Service. Added
        getXml, setInterval and setDescription functions.

        * pandora.h: Commentary fixed.

        * Changelog: Renamed to ChangeLog.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@83 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
This commit is contained in:
Esteban Sanchez 2006-07-04 14:07:08 +00:00
parent e602fbb96d
commit 54a0db6509
50 changed files with 14919 additions and 157 deletions

View File

@ -0,0 +1,29 @@
2006-07-04 Esteban Sanchez <esteban@steve-o.org>
* windows/pandora_wmi.*, windows/pandora_windows_info.*, windows/wmi/disphelper.*,
misc/pandora_file.*, ssh/*, ssh/libssh2/*, modules/pandora_module_service.*,
modules/pandora_module_proc.*: Added to repository
* pandora_windows_service.cc, pandora_windows_service.h: getXMLHeader renamed to getXmlHeader
and modified its behavior. Updated to the Pandora XML specification. Add SSH and XML generation
functionallity.
* modules/pandora_module_exec.cc: Added the execution to a job to prevent zombies process. Update
the execution command.
* modules/pandora_module_factory.cc: Added Pandora_Module_Proc and Pandora_Module_Service. Added
the interval parameter.
* modules/pandora_module_list.cc: Added support to Pandora_Module_Proc and Pandora_Module_Service.
* modules/pandora_module.h: Added new types of modules. Added execution times and module description
to the Pandora_Module class. Added support to Pandora_Module_Proc and Pandora_Module_Service. Added
getXml, setInterval and setDescription functions.
* pandora.h: Commentary fixed.
* Changelog: Renamed to ChangeLog
2006-06-20 Esteban Sanchez
* Initial import.

View File

@ -1,3 +0,0 @@
2006-06-20 Esteban Sánchez
* Initial import.

View File

@ -1,7 +1,7 @@
[Project]
FileName=PandoraAgent.dev
Name=PandoraAgent
UnitCount=25
UnitCount=59
Type=1
Ver=1
ObjFiles=
@ -12,22 +12,22 @@ ResourceIncludes=
MakeIncludes=
Compiler=
CppCompiler=
Linker=
Linker=-lole32 -loleaut32 -luuid_@@_e:/work/common/Dev-Cpp/lib/libws2_32.a_@@_e:/work/common/Dev-Cpp/lib/libpsapi.a_@@_e:/work/common/Dev-Cpp/lib/libws2_32.a_@@_e:/work/common/Dev-Cpp/lib/libeay32.a_@@_e:/work/common/Dev-Cpp/lib/libz.lib_@@_e:/work/common/Dev-Cpp/lib/libiphlpapi.a_@@_e:/work/common/Dev-Cpp/lib/libnetapi32.a_@@_
IsCpp=1
Icon=
ExeOutput=
ObjectOutput=
OverrideOutput=0
OverrideOutputName=
OverrideOutputName=PandoraAgent.exe
HostApplication=
Folders=Modules,Modules/Utils,XML
Folders=Misc,Modules,Modules/Utils,SSH,SSH/libssh2,Windows,Windows/WMI,XML
CommandLine=
UseCustomMakefile=0
CustomMakefile=
IncludeVersionInfo=0
SupportXPThemes=0
CompilerSet=0
CompilerSettings=
CompilerSettings=0000000000000001000000
[Unit1]
FileName=main.cc
@ -198,7 +198,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit16]
FileName=pandora_strutils.cpp
FileName=pandora_strutils.cc
CompileCpp=1
Folder=
Compile=1
@ -257,30 +257,20 @@ Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit26]
FileName=modules\pandora_module_factory.h
CompileCpp=1
Folder=Modules/Utils
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit28]
FileName=modules\pandora_module.cc
CompileCpp=1
Folder=Modules
FileName=windows\wmi\disphelper.c
CompileCpp=0
Folder=Windows/WMI
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
BuildCmd=$(CC) -c disphelper.c -o disphelper.o $(CFLAGS)
[Unit29]
FileName=modules\pandora_module_generic_data_inc.cc
FileName=windows\wmi\disphelper.h
CompileCpp=1
Folder=Modules
Folder=Windows/WMI
Compile=1
Link=1
Priority=1000
@ -288,7 +278,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit30]
FileName=modules\pandora_module_generic_proc.cc
FileName=modules\pandora_module_proc.h
CompileCpp=1
Folder=Modules
Compile=1
@ -298,7 +288,7 @@ OverrideBuildCmd=0
BuildCmd=
[Unit31]
FileName=modules\pandora_module_generic_data_string.cc
FileName=modules\pandora_module_proc.cc
CompileCpp=1
Folder=Modules
Compile=1
@ -308,19 +298,9 @@ OverrideBuildCmd=0
BuildCmd=
[Unit33]
FileName=modules\pandora_module_exec.cc
FileName=ssh\pandora_ssh_client.cc
CompileCpp=1
Folder=Modules
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit32]
FileName=modules\pandora_module_exec.h
CompileCpp=1
Folder=Modules
Folder=SSH
Compile=1
Link=1
Priority=1000
@ -367,3 +347,293 @@ Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit26]
FileName=windows\pandora_wmi.cc
CompileCpp=1
Folder=Windows
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit27]
FileName=windows\pandora_wmi.h
CompileCpp=1
Folder=Windows
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit32]
FileName=ssh\pandora_ssh_client.h
CompileCpp=1
Folder=SSH
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit34]
FileName=ssh\libssh2\userauth.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit35]
FileName=ssh\libssh2\comp.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit36]
FileName=ssh\libssh2\crypt.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit37]
FileName=ssh\libssh2\kex.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit38]
FileName=ssh\libssh2\libssh2.h
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit39]
FileName=ssh\libssh2\libssh2_config.h
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit40]
FileName=ssh\libssh2\libssh2_publickey.h
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit41]
FileName=ssh\libssh2\mac.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit42]
FileName=ssh\libssh2\packet.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit43]
FileName=ssh\libssh2\publickey.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit44]
FileName=ssh\libssh2\scp.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit45]
FileName=ssh\libssh2\session.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit47]
FileName=ssh\libssh2\libssh2_priv.h
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit48]
FileName=ssh\libssh2\libssh2_sftp.h
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit49]
FileName=ssh\libssh2\misc.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit50]
FileName=ssh\libssh2\sftp.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit51]
FileName=ssh\libssh2\channel.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit52]
FileName=ssh\pandora_ssh_test.h
CompileCpp=1
Folder=SSH
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit53]
FileName=ssh\pandora_ssh_test.cc
CompileCpp=1
Folder=SSH
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit46]
FileName=ssh\libssh2\hostkey.c
CompileCpp=1
Folder=SSH/libssh2
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit54]
FileName=misc\pandora_file.cc
CompileCpp=1
Folder=Misc
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit55]
FileName=misc\pandora_file.h
CompileCpp=1
Folder=Misc
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit56]
FileName=windows\pandora_windows_info.h
CompileCpp=1
Folder=Windows
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit57]
FileName=windows\pandora_windows_info.cc
CompileCpp=1
Folder=Windows
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit59]
FileName=modules\pandora_module_service.cc
CompileCpp=1
Folder=Modules
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=
[Unit58]
FileName=modules\pandora_module_service.h
CompileCpp=1
Folder=Modules
Compile=1
Link=1
Priority=1000
OverrideBuildCmd=0
BuildCmd=

View File

@ -59,9 +59,8 @@ main (int argc, char *argv[]) {
return 1;
}
}
//service->run ();
service->pandora_init ();
service->pandora_run ();
service->run ();
delete service;
return 0;
}

View File

@ -0,0 +1,63 @@
/* Misc utils for files.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_file.h"
#include <fstream>
#include <stdio.h>
#include <windows.h>
using namespace std;
string
Pandora_File::readFile (const string filename) {
string line, result;
ifstream myfile (filename.c_str ());
if (! myfile.is_open ()) {
throw File_Not_Found ();
}
if (myfile.is_open()) {
while (! myfile.eof()) {
getline (myfile,line);
result += line + '\n';
}
myfile.close();
}
return result;
}
void
Pandora_File::removeFile (const string filename) {
if (remove (filename.c_str ()) == -1) {
throw Delete_Error ();
}
}
void
Pandora_File::writeFile (const string filename, const string data) {
ofstream file (filename.c_str ());
if (! file.is_open ()) {
throw File_Not_Found ();
}
file.write (data.c_str (), data.length ());
file.close ();
}

View File

@ -0,0 +1,41 @@
/* Misc utils for files.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_FILE_H__
#define __PANDORA_FILE_H__
#include <string>
#include "../pandora.h"
using namespace std;
namespace Pandora_File {
class File_Not_Found : Pandora::Pandora_Exception {
};
class Delete_Error : Pandora::Pandora_Exception {
};
string readFile (const string filename);
void removeFile (const string filename);
void writeFile (const string filename, const string data);
}
#endif

View File

@ -20,11 +20,20 @@
#include "pandora_module.h"
#include "../pandora_strutils.h"
#include "../pandora.h"
using namespace Pandora;
using namespace Pandora_Modules;
using namespace Pandora_Strutils;
Pandora_Module::Pandora_Module (string name) {
this->module_name = name;
this->module_name = name;
this->executions = 0;
this->module_interval = 1;
this->output = "";
this->max = 0;
this->min = 0;
this->has_limits = false;
}
Pandora_Module::~Pandora_Module () {
@ -97,6 +106,62 @@ Pandora_Module::run () {
}
TiXmlElement *
Pandora_Module::getXml () {
string data;
TiXmlElement *root;
TiXmlElement *element;
TiXmlText *text;
string item_str, data_str, desc_str;
pandoraDebug ("%s getXML begin", module_name.c_str ());
try {
data = this->getOutput ();
} catch (Output_Error e) {
pandoraLog ("Output error");
return NULL;
} catch (Interval_Error e) {
pandoraLog ("The returned value was not in the interval");
return NULL;
}
root = new TiXmlElement ("module");
element = new TiXmlElement ("name");
text = new TiXmlText (this->module_name);
element->InsertEndChild (*text);
root->InsertEndChild (*element);
delete element;
delete text;
element = new TiXmlElement ("type");
text = new TiXmlText (this->module_type_str);
element->InsertEndChild (*text);
root->InsertEndChild (*element);
delete element;
delete text;
element = new TiXmlElement ("data");
data_str = strreplace (this->output,
"%", "%%" );
text = new TiXmlText (data_str);
element->InsertEndChild (*text);
root->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("description");
text = new TiXmlText (this->module_description);
element->InsertEndChild (*text);
root->InsertEndChild (*element);
delete text;
delete element;
pandoraDebug ("%s getXML end", module_name.c_str ());
return root;
}
void
Pandora_Module::setMax (int value) {
this->has_limits = true;
@ -114,3 +179,14 @@ Pandora_Module::setType (string type) {
this->module_type_str = type;
this->module_type = getModuleType (type);
}
void
Pandora_Module::setInterval (int interval) {
this->module_interval = interval;
}
void
Pandora_Module::setDescription (string description) {
pandoraDebug ("Set description to: %s", description.c_str ());
this->module_description = description;
}

View File

@ -43,9 +43,14 @@ namespace Pandora_Modules {
enum {
MODULE_0,
MODULE_EXEC
MODULE_EXEC,
MODULE_PROC,
MODULE_SERVICE
};
const string module_exec_str = "module_exec";
const string module_proc_str = "module_proc";
const string module_service_str = "module_service";
class Output_Error : public Pandora::Pandora_Exception { };
class Interval_Error : public Pandora::Pandora_Exception { };
@ -56,8 +61,10 @@ namespace Pandora_Modules {
string module_type_str;
int module_type;
string module_kind_str;
string module_description;
int module_kind;
int module_interval;
int executions;
string output;
int max, min;
bool has_limits;
@ -70,7 +77,7 @@ namespace Pandora_Modules {
void setInterval (int interval);
/* Get the XML output of the agent. */
TiXmlElement *getXML ();
TiXmlElement *getXml ();
/* Execute the agent */
virtual void run ();
@ -83,6 +90,7 @@ namespace Pandora_Modules {
int getModuleKind () const;
void setType (string type);
void setDescription (string description);
void setMax (int value);
void setMin (int value);
};

View File

@ -19,7 +19,6 @@
*/
#include "pandora_module_exec.h"
#include "pandora_module.h"
#include "../pandora_strutils.h"
#include <windows.h>
@ -31,7 +30,7 @@ using namespace Pandora_Modules;
Pandora_Module_Exec::Pandora_Module_Exec (string name, string exec)
: Pandora_Module (name) {
this->module_exec = "cmd.exe /c " + exec;
this->module_exec = "cmd.exe /c \"" + exec + "\"";
this->module_kind_str = module_exec_str;
this->module_kind = MODULE_EXEC;
@ -43,21 +42,41 @@ Pandora_Module_Exec::run () {
PROCESS_INFORMATION pi;
DWORD retval;
SECURITY_ATTRIBUTES attributes;
HANDLE out, new_stdout, out_read;
HANDLE out, new_stdout, out_read, job;
string working_dir;
this->output = "";
/* Check the interval */
if (this->executions % this->module_interval != 0) {
pandoraDebug ("Interval is not fulfilled");
this->executions++;
return;
}
/* Increment the executions after check. This is done to execute the
first time */
this->executions++;
/* Set the bInheritHandle flag so pipe handles are inherited. */
attributes.nLength = sizeof (SECURITY_ATTRIBUTES);
attributes.bInheritHandle = TRUE;
attributes.lpSecurityDescriptor = NULL;
/* Create a job to kill the child tree if it become zombie */
/* CAUTION: In order to work this, WINVER should be defined to 0x0500.
It is defined in <windef.h> */
job = CreateJobObject (&attributes, this->module_name.c_str ());
if (job == NULL) {
pandoraLog ("CreateJobObject bad. Err: %d", GetLastError ());
return;
}
/* Get the handle to the current STDOUT. */
out = GetStdHandle (STD_OUTPUT_HANDLE);
if (! CreatePipe (&out_read, &new_stdout, &attributes, 0)) {
pandoraLog ("CreatePipe failed");
pandoraLog ("CreatePipe failed. Err: %d", GetLastError ());
return;
}
@ -83,22 +102,32 @@ Pandora_Module_Exec::run () {
working_dir = getPandoraInstallDir () + "util\\";
/* Create the child process. */
if (! CreateProcess (NULL, (CHAR *) this->module_exec.c_str (), NULL, NULL, TRUE,
CREATE_NEW_CONSOLE, NULL, working_dir.c_str (),
&si, &pi)) {
pandoraLog ("Babel_Windows_Password: %s CreateProcess failed (%d)",
if (! CreateProcess (NULL, (CHAR *) this->module_exec.c_str (), NULL,
NULL, TRUE, CREATE_SUSPENDED, NULL,
working_dir.c_str (), &si, &pi)) {
pandoraLog ("Pandora_Module_Exec: %s CreateProcess failed. Err: %d",
this->module_name.c_str (), GetLastError ());
} else {
char buffer[BUFSIZE + 1];
unsigned long read, avail;
if (! AssignProcessToJobObject (job, pi.hProcess)) {
pandoraLog ("Assign bad %d", GetLastError ());
}
ResumeThread (pi.hThread);
/* Wait until process exits. */
/* TODO: This should not be infinite, but just a few seconds */
WaitForSingleObject (pi.hProcess, INFINITE);
/* TODO: The time should be an attribute*/
WaitForSingleObject (pi.hProcess, 15000);
GetExitCodeProcess (pi.hProcess, &retval);
if (retval != 0) {
pandoraLog ("Pandora_Module: %s did not executed well (retcode: %d)",
if (! TerminateJobObject (job, 0)) {
pandoraLog ("TerminateJobObject failed. Err: %d",
GetLastError ());
}
pandoraLog ("Pandora_Module_Exec: %s did not executed well (retcode: %d)",
this->module_name.c_str (), retval);
}
@ -109,12 +138,13 @@ Pandora_Module_Exec::run () {
do {
ReadFile (out_read, buffer, BUFSIZE, &read,
NULL);
buffer[read] = '\0';
this->output += (char *) buffer;
memset (buffer, 0, BUFSIZE);
} while (read >= BUFSIZE);
}
/* Close process and thread handles. */
/* Close job, process and thread handles. */
CloseHandle (job);
CloseHandle (pi.hProcess);
CloseHandle (pi.hThread);
}

View File

@ -18,6 +18,9 @@
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_MODULE_EXEC_H__
#define __PANDORA_MODULE_EXEC_H__
#include "pandora_module.h"
namespace Pandora_Modules {
@ -30,3 +33,5 @@ namespace Pandora_Modules {
void run ();
};
}
#endif

View File

@ -21,6 +21,8 @@
#include "pandora_module_factory.h"
#include "pandora_module.h"
#include "pandora_module_exec.h"
#include "pandora_module_proc.h"
#include "pandora_module_service.h"
#include "../pandora_strutils.h"
#include <list>
@ -32,9 +34,11 @@ using namespace Pandora_Strutils;
#define TOKEN_TYPE ("module_type ")
#define TOKEN_INTERVAL ("module_interval ")
#define TOKEN_EXEC ("module_exec ")
#define TOKEN_PROC ("module_proc ")
#define TOKEN_SERVICE ("module_service ")
#define TOKEN_MAX ("module_max ")
#define TOKEN_MIN ("module_min ")
#define TOKEN_DESCRIPTION ("module_descripcion ")
#define TOKEN_DESCRIPTION ("module_description ")
string
parseLine (string line, string token) {
@ -54,10 +58,21 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
list<string>::iterator iter;
string module_name, module_type, module_exec;
string module_min, module_max, module_description;
string module_interval;
string module_interval, module_proc, module_service;
Pandora_Module *module;
bool numeric;
module_name = "";
module_type = "";
module_min = "";
module_max = "";
module_description = "";
module_interval = "";
module_exec = "";
module_proc = "";
module_service = "";
stringtok (tokens, definition, "\n");
/* Pick the first and the last value of the token list */
@ -79,6 +94,12 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
if (module_exec == "") {
module_exec = parseLine (line, TOKEN_EXEC);
}
if (module_proc == "") {
module_proc = parseLine (line, TOKEN_PROC);
}
if (module_service == "") {
module_service = parseLine (line, TOKEN_SERVICE);
}
if (module_max == "") {
module_max = parseLine (line, TOKEN_MAX);
}
@ -95,10 +116,20 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
if (module_exec != "") {
module = new Pandora_Module_Exec (module_name,
module_exec);
} else if (module_proc != "") {
module = new Pandora_Module_Proc (module_name,
module_proc);
} else if (module_service != "") {
module = new Pandora_Module_Service (module_name,
module_service);
} else {
return NULL;
}
pandoraDebug ("Description %s", module_description.c_str ());
if (module_description != "") {
module->setDescription (module_description);
}
switch (Pandora_Module::getModuleType (module_type)) {
case TYPE_GENERIC_DATA:
case TYPE_GENERIC_DATA_INC:
@ -145,5 +176,18 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
}
}
}
if (module_interval != "") {
int interval;
try {
interval = strtoint (module_interval);
module->setInterval (interval);
} catch (Invalid_Conversion e) {
pandoraLog ("Invalid interval value \"%s\" for module %s",
module_interval.c_str (),
module_name.c_str ());
}
}
return module;
}

View File

@ -21,14 +21,14 @@
#include "pandora_module_factory.h"
#include "pandora_module_list.h"
#include "pandora_module_exec.h"
#include "pandora_module_proc.h"
#include "pandora_module_service.h"
#include <fstream>
using namespace std;
using namespace Pandora;
using namespace Pandora_Module_Factory;
Pandora_Module_List::Pandora_Module_List (string filename) {
ifstream file (filename.c_str ());
string buffer;
@ -85,8 +85,10 @@ Pandora_Module_List::~Pandora_Module_List () {
void
Pandora_Module_List::parseModuleDefinition (string definition) {
Pandora_Module *module;
Pandora_Module_Exec *module_exec;
Pandora_Module *module;
Pandora_Module_Exec *module_exec;
Pandora_Module_Proc *module_proc;
Pandora_Module_Service *module_service;
module = getModuleFromDefinition (definition);
@ -96,6 +98,17 @@ Pandora_Module_List::parseModuleDefinition (string definition) {
module_exec = (Pandora_Module_Exec *) module;
modules->push_back (module_exec);
break;
case MODULE_PROC:
module_proc = (Pandora_Module_Proc *) module;
modules->push_back (module_proc);
break;
case MODULE_SERVICE:
module_service = (Pandora_Module_Service *) module;
modules->push_back (module_service);
break;
default:
break;

View File

@ -0,0 +1,49 @@
/* Pandora proc module. These modules check if a program is alive in the system.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_module_proc.h"
#include "../windows/pandora_wmi.h"
#include "../pandora_strutils.h"
#include <algorithm>
#include <cctype>
using namespace Pandora;
using namespace Pandora_Modules;
using namespace Pandora_Strutils;
Pandora_Module_Proc::Pandora_Module_Proc (string name, string process_name)
: Pandora_Module (name) {
transform (process_name.begin (), process_name.end (),
this->process_name.begin (), (int (*) (int)) tolower);
this->module_kind_str = module_proc_str;
this->module_kind = MODULE_PROC;
}
void
Pandora_Module_Proc::run () {
pandoraDebug ("MODULE_PROC RUN");
int res = Pandora_Wmi::isProcessRunning (this->process_name);
pandoraDebug ("res: %d", res);
output = "1";
}

View File

@ -0,0 +1,37 @@
/* Pandora proc module. These modules check if a program is alive in the system.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_MODULE_PROC_H__
#define __PANDORA_MODULE_PROC_H__
#include "pandora_module.h"
namespace Pandora_Modules {
class Pandora_Module_Proc : public Pandora_Module {
private:
string process_name;
public:
Pandora_Module_Proc (string name, string process_name);
void run ();
};
}
#endif

View File

@ -0,0 +1,47 @@
/* Pandora service module. These modules check if a service is running in the
system.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_module_service.h"
#include "../windows/pandora_wmi.h"
#include "../pandora_strutils.h"
#include <algorithm>
#include <cctype>
using namespace Pandora;
using namespace Pandora_Modules;
using namespace Pandora_Strutils;
Pandora_Module_Service::Pandora_Module_Service (string name, string service_name)
: Pandora_Module (name) {
transform (service_name.begin (), service_name.end (),
this->service_name.begin (), (int (*) (int)) tolower);
this->module_kind_str = module_service_str;
this->module_kind = MODULE_SERVICE;
}
void
Pandora_Module_Service::run () {
pandoraDebug ("MODULE_SERVICE RUN");
output = inttostr (Pandora_Wmi::isServiceRunning (this->service_name));
}

View File

@ -0,0 +1,38 @@
/* Pandora service module. These modules check if a service is running in the
system.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_MODULE_SERVICE_H__
#define __PANDORA_MODULE_SERVICE_H__
#include "pandora_module.h"
namespace Pandora_Modules {
class Pandora_Module_Service : public Pandora_Module {
private:
string service_name;
public:
Pandora_Module_Service (string name, string service_name);
void run ();
};
}
#endif

View File

@ -159,3 +159,4 @@ void
Pandora::setPandoraDebug (bool dbg) {
pandora_debug = dbg;
}

View File

@ -59,4 +59,4 @@ namespace Pandora {
class Pandora_Exception { };
}
#endif /* __BABEL_H__ */
#endif /* __PANDORA_H__ */

View File

@ -34,6 +34,7 @@ Pandora_Agent_Conf::Pandora_Agent_Conf (string filename) {
this->key_values = new list<Key_Value> ();
if (!file.is_open ()) {
pandoraDebug ("No hay conf");
return;
}

View File

@ -44,6 +44,5 @@ namespace Pandora_Strutils {
void
stringtok (list<string> &l, string const &s,
char const * const separators = " \t\n");
}
#endif /* __STRUTILS_H__ */

View File

@ -20,13 +20,13 @@
#include "pandora_windows_service.h"
#include "pandora.h"
#include "pandora_strutils.h"
#include "windows_service.h"
#include "modules/pandora_module_factory.h"
#include "ssh/pandora_ssh_client.h"
#include "misc/pandora_file.h"
#include "windows/pandora_windows_info.h"
#include "modules/pandora_module_generic_data.h"
#include "modules/pandora_module_generic_data_inc.h"
#include "modules/pandora_module_generic_data_string.h"
#include "modules/pandora_module_generic_proc.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
@ -34,12 +34,12 @@
using namespace std;
using namespace Pandora;
using namespace Pandora_Modules;
using namespace Pandora_Strutils;
Pandora_Windows_Service::Pandora_Windows_Service (const char * svc_name,
const char * svc_display_name,
const char * svc_description)
: Windows_Service (svc_name, svc_display_name, svc_description)
{
: Windows_Service (svc_name, svc_display_name, svc_description) {
this->setInitFunction ((void (Windows_Service::*) ()) &Pandora_Windows_Service::pandora_init);
this->setRunFunction ((void (Windows_Service::*) ()) &Pandora_Windows_Service::pandora_run);
@ -74,85 +74,55 @@ Pandora_Windows_Service::pandora_init () {
this->setSleepTime (interval_ms);
pandoraDebug ("Init end");
return;
}
void
Pandora_Windows_Service::addXMLHeader (TiXmlElement *root) {
TiXmlElement *
Pandora_Windows_Service::getXmlHeader () {
TiXmlElement *agent;
TiXmlElement *element;
TiXmlText *text;
SYSTEMTIME st;
char timestamp[20];
string value;
agent = new TiXmlElement ("agent");
element = new TiXmlElement ("name");
agent = new TiXmlElement ("agent_data");
/* TODO: Get the name of the machine if there is no agent_name*/
text = new TiXmlText ("agent_name");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("version");
value = conf->getValue ("agent_name");
agent->SetAttribute ("agent_name", value);
/* TODO: Get the real version of the agent */
text = new TiXmlText ("1.0Beta");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("timestamp");
agent->SetAttribute ("version", "1.2Beta");
GetSystemTime(&st);
sprintf (timestamp, "%d/%d/%d %d:%d:%d", st.wDay, st.wMonth,
st.wYear, st.wHour, st.wMinute, st.wSecond);
text = new TiXmlText (timestamp);
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("interval");
text = new TiXmlText ("interval");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("os");
/* TODO */
text = new TiXmlText ("Windows");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("os_version");
/* TODO */
text = new TiXmlText ("XP");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
element = new TiXmlElement ("os_build");
/* TODO */
text = new TiXmlText ("1");
element->InsertEndChild (*text);
agent->InsertEndChild (*element);
delete text;
delete element;
root->InsertEndChild (*agent);
delete agent;
agent->SetAttribute ("timestamp", timestamp);
value = conf->getValue ("interval");
agent->SetAttribute ("interval", value);
value = Pandora_Windows_Info::getOSName ();
agent->SetAttribute ("os", value);
value = Pandora_Windows_Info::getOSVersion ();
agent->SetAttribute ("os_version", value);
return agent;
}
void
Pandora_Windows_Service::pandora_run () {
TiXmlDocument *doc;
TiXmlElement *local_xml, *agent;
string xml_filename, remote_host;
string remote_filepath, random_integer;
string tmp_filename, tmp_filepath, interval;
string pubkey_file, privkey_file;
bool saved;
pandoraDebug ("Run begin");
agent = getXmlHeader ();
execution_number++;
if (this->modules != NULL) {
@ -167,18 +137,92 @@ Pandora_Windows_Service::pandora_run () {
pandoraDebug ("Run %s", module->getName ().c_str ());
module->run ();
try {
result = module->getOutput ();
pandoraDebug ("Result: %s", result.c_str ());
} catch (Output_Error e) {
pandoraLog ("Output error");
} catch (Interval_Error e) {
pandoraLog ("The returned value was not in the interval");
}
local_xml = module->getXml ();
agent->InsertEndChild (*local_xml);
delete local_xml;
this->modules->goNext ();
}
}
random_integer = inttostr (rand());
tmp_filename = conf->getValue ("agent_name");
tmp_filename += "." + random_integer + ".data";
xml_filename = conf->getValue ("temporal");
if (xml_filename[xml_filename.length () - 1] != '\\') {
xml_filename += "\\";
}
tmp_filepath = xml_filename + tmp_filename;
/* Copy the XML to a temporal file */
pandoraDebug ("Copying XML on %s", tmp_filepath.c_str ());
doc = new TiXmlDocument (tmp_filepath);
doc->InsertEndChild (*agent);
saved = doc->SaveFile();
delete doc;
delete agent;
if (!saved) {
pandoraLog ("Error when saving the XML in %s",
tmp_filepath.c_str ());
return;
}
remote_host = conf->getValue ("server_ip");
ssh_client = new SSH::Pandora_Ssh_Client ();
pandoraDebug ("Connecting with %s", remote_host.c_str ());
try {
pubkey_file = Pandora::getPandoraInstallDir ();
pubkey_file += "key\\id_dsa.pub";
privkey_file = Pandora::getPandoraInstallDir ();
privkey_file += "key\\id_dsa";
pandoraDebug ("Pub: %s Priv: %s", pubkey_file.c_str (),
privkey_file.c_str ());
ssh_client->connectWithPublicKey (remote_host.c_str (), 22, "babel",
pubkey_file, privkey_file, "");
} catch (SSH::Authentication_Failed e) {
delete ssh_client;
pandoraLog ("Pandora Agent: Authentication Failed when connecting to %s",
remote_host.c_str ());
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
return;
} catch (Pandora_Exception e) {
delete ssh_client;
pandoraLog ("Pandora Agent: Failed when copying to %s", remote_host.c_str ());
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
return;
}
remote_filepath = conf->getValue ("server_path");
if (remote_filepath[remote_filepath.length () - 1] != '/') {
remote_filepath += "/";
}
pandoraDebug ("Remote copying XML %s on server %s at %s%s",
tmp_filepath.c_str (), remote_host.c_str (),
remote_filepath.c_str (), tmp_filename.c_str ());
try {
ssh_client->scpFileFilename (remote_filepath + tmp_filename,
tmp_filepath);
} catch (Pandora_Exception e) {
ssh_client->disconnect();
delete ssh_client;
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
return;
}
ssh_client->disconnect();
pandoraDebug ("Execution number %d", execution_number);

View File

@ -26,25 +26,26 @@
#include "tinyxml/tinyxml.h"
#include "pandora_agent_conf.h"
#include "modules/pandora_module_list.h"
#include "ssh/pandora_ssh_client.h"
using namespace std;
class Pandora_Windows_Service : public Windows_Service {
private:
//SSH::Babel_Ssh_Client *ssh_client;
Pandora_Agent_Conf *conf;
Pandora_Module_List *modules;
long execution_number;
SSH::Pandora_Ssh_Client *ssh_client;
Pandora_Agent_Conf *conf;
Pandora_Module_List *modules;
long execution_number;
void addXMLHeader (TiXmlElement *root);
public:
void pandora_run ();
void pandora_init ();
TiXmlElement * getXmlHeader ();
void pandora_run ();
void pandora_init ();
public:
Pandora_Windows_Service (const char * svc_name,
const char * svc_display_name,
const char * svc_description);
~Pandora_Windows_Service ();
Pandora_Windows_Service (const char * svc_name,
const char * svc_display_name,
const char * svc_description);
~Pandora_Windows_Service ();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <zlib.h>
/* ********
* none *
******** */
/* {{{ libssh2_comp_method_none_comp
* Minimalist compression: Absolutely none
*/
static int libssh2_comp_method_none_comp(LIBSSH2_SESSION *session, int compress,
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
const unsigned char *src, unsigned long src_len, void **abstract)
{
*dest = (unsigned char *)src;
*dest_len = src_len;
*free_dest = 0;
return 0;
}
/* }}} */
static LIBSSH2_COMP_METHOD libssh2_comp_method_none = {
"none",
NULL,
libssh2_comp_method_none_comp,
NULL
};
#ifdef LIBSSH2_HAVE_ZLIB
/* ********
* zlib *
******** */
/* {{{ Memory management wrappers
* Yes, I realize we're doing a callback to a callback,
* Deal...
*/
static voidpf libssh2_comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
{
LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)opaque;
return (voidpf)LIBSSH2_ALLOC(session, items * size);
}
static void libssh2_comp_method_zlib_free(voidpf opaque, voidpf address)
{
LIBSSH2_SESSION *session = (LIBSSH2_SESSION*)opaque;
LIBSSH2_FREE(session, address);
}
/* }}} */
/* {{{ libssh2_comp_method_zlib_init
* All your bandwidth are belong to us (so save some)
*/
static int libssh2_comp_method_zlib_init(LIBSSH2_SESSION *session, int compress, void **abstract)
{
z_stream *strm;
int status;
strm = (z_stream *) LIBSSH2_ALLOC(session, sizeof(z_stream));
if (!strm) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for zlib compression/decompression", 0);
return -1;
}
memset(strm, 0, sizeof(z_stream));
strm->opaque = (voidpf)session;
strm->zalloc = (alloc_func)libssh2_comp_method_zlib_alloc;
strm->zfree = (free_func)libssh2_comp_method_zlib_free;
if (compress) {
/* deflate */
status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
} else {
/* inflate */
status = inflateInit(strm);
}
if (status != Z_OK) {
LIBSSH2_FREE(session, strm);
return -1;
}
*abstract = strm;
return 0;
}
/* }}} */
/* {{{ libssh2_comp_method_zlib_comp
* zlib, a compression standard for all occasions
*/
static int libssh2_comp_method_zlib_comp(LIBSSH2_SESSION *session, int compress,
unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
const unsigned char *src, unsigned long src_len, void **abstract)
{
z_stream *strm = (z_stream *) *abstract;
/* A short-term alloc of a full data chunk is better than a series of reallocs */
char *out;
int out_maxlen = compress ? (src_len + 4) : (2 * src_len);
int limiter = 0;
/* In practice they never come smaller than this */
if (out_maxlen < 25) {
out_maxlen = 25;
}
if (out_maxlen > (int) payload_limit) {
out_maxlen = payload_limit;
}
strm->next_in = (Bytef *)src;
strm->avail_in = src_len;
strm->next_out = (Bytef *) LIBSSH2_ALLOC(session, out_maxlen);
out = (char *) strm->next_out;
strm->avail_out = out_maxlen;
if (!strm->next_out) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate compression/decompression buffer", 0);
return -1;
}
while (strm->avail_in) {
int status;
if (compress) {
status = deflate(strm, Z_PARTIAL_FLUSH);
} else {
status = inflate(strm, Z_PARTIAL_FLUSH);
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
LIBSSH2_FREE(session, out);
return -1;
}
if (strm->avail_in) {
unsigned long out_ofs = out_maxlen - strm->avail_out;
out_maxlen += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
if ((out_maxlen > (int) payload_limit) && !compress && limiter++) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, out);
return -1;
}
out = (char *) LIBSSH2_REALLOC(session, out, out_maxlen);
if (!out) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand compress/decompression buffer", 0);
return -1;
}
strm->next_out = (Bytef *) out + out_ofs;
strm->avail_out += compress ? (strm->avail_in + 4) : (2 * strm->avail_in);
} else while (!strm->avail_out) {
/* Done with input, might be a byte or two in internal buffer during compress
* Or potentially many bytes if it's a decompress
*/
int grow_size = compress ? 8 : 1024;
if (out_maxlen >= (int) payload_limit) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "Excessive growth in decompression phase", 0);
LIBSSH2_FREE(session, out);
return -1;
}
if (grow_size > (int) (payload_limit - out_maxlen)) {
grow_size = payload_limit - out_maxlen;
}
out_maxlen += grow_size;
strm->avail_out = grow_size;
out = (char *) LIBSSH2_REALLOC(session, out, out_maxlen);
if (!out) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to expand final compress/decompress buffer", 0);
return -1;
}
strm->next_out = (Bytef *) out + out_maxlen - grow_size;
if (compress) {
status = deflate(strm, Z_PARTIAL_FLUSH);
} else {
status = inflate(strm, Z_PARTIAL_FLUSH);
}
if (status != Z_OK) {
libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compress/decompression failure", 0);
LIBSSH2_FREE(session, out);
return -1;
}
}
}
*dest = (unsigned char *) out;
*dest_len = out_maxlen - strm->avail_out;
*free_dest = 1;
return 0;
}
/* }}} */
/* {{{ libssh2_comp_method_zlib_dtor
* All done, no more compression for you
*/
static int libssh2_comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compress, void **abstract)
{
z_stream *strm = (z_stream *) *abstract;
if (strm) {
if (compress) {
/* deflate */
deflateEnd(strm);
} else {
/* inflate */
inflateEnd(strm);
}
LIBSSH2_FREE(session, strm);
}
*abstract = NULL;
return 0;
}
/* }}} */
static LIBSSH2_COMP_METHOD libssh2_comp_method_zlib = {
"zlib",
libssh2_comp_method_zlib_init,
libssh2_comp_method_zlib_comp,
libssh2_comp_method_zlib_dtor,
};
#endif /* LIBSSH2_HAVE_ZLIB */
/* ***********************
* Compression Methods *
*********************** */
static LIBSSH2_COMP_METHOD *_libssh2_comp_methods[] = {
&libssh2_comp_method_none,
#ifdef LIBSSH2_HAVE_ZLIB
&libssh2_comp_method_zlib,
#endif /* LIBSSH2_HAVE_ZLIB */
NULL
};
LIBSSH2_COMP_METHOD **libssh2_comp_methods(void) {
return _libssh2_comp_methods;
}

View File

@ -0,0 +1,189 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <openssl/evp.h>
#ifdef LIBSSH2_CRYPT_NONE
/* {{{ libssh2_crypt_none_crypt
* Minimalist cipher: VERY secure *wink*
*/
static int libssh2_crypt_none_crypt(LIBSSH2_SESSION *session, unsigned char *buf, void **abstract)
{
/* Do nothing to the data! */
return 0;
}
/* }}} */
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
"none",
8, /* blocksize (SSH2 defines minimum blocksize as 8) */
0, /* iv_len */
0, /* secret_len */
0, /* flags */
NULL,
libssh2_crypt_none_crypt,
NULL
};
#endif
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
"3des-cbc",
8, /* blocksize */
8, /* initial value length */
24, /* secret length */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **)) EVP_des_ede3_cbc,
NULL,
};
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
"aes128-cbc",
16, /* blocksize */
16, /* initial value length */
16, /* secret length -- 16*8 == 128bit */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_aes_128_cbc,
NULL,
};
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
"aes192-cbc",
16, /* blocksize */
16, /* initial value length */
24, /* secret length -- 24*8 == 192bit */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_aes_192_cbc,
NULL,
};
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
"aes256-cbc",
16, /* blocksize */
16, /* initial value length */
32, /* secret length -- 32*8 == 256bit */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_aes_256_cbc,
NULL,
};
/* rijndael-cbc@lysator.liu.se == aes256-cbc */
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
"rijndael-cbc@lysator.liu.se",
16, /* blocksize */
16, /* initial value length */
32, /* secret length -- 32*8 == 256bit */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_aes_256_cbc,
NULL,
};
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)*/
#ifndef OPENSSL_NO_BLOWFISH
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
"blowfish-cbc",
8, /* blocksize */
8, /* initial value length */
16, /* secret length */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_bf_cbc,
NULL,
};
#endif /* ! OPENSSL_NO_BLOWFISH */
#ifndef OPENSSL_NO_CAST
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
"cast128-cbc",
8, /* blocksize */
8, /* initial value length */
16, /* secret length */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_cast5_cbc,
NULL,
};
#endif /* ! OPENSSL_NO_CAST */
#ifndef OPENSSL_NO_RC4
static LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
"arcfour",
8, /* blocksize */
8, /* initial value length */
16, /* secret length */
LIBSSH2_CRYPT_METHOD_FLAG_EVP,
NULL,
(int (*)(LIBSSH2_SESSION *, unsigned char *, void **))EVP_rc4,
NULL,
};
#endif /* ! OPENSSL_NO_RC4 */
static LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)
&libssh2_crypt_method_aes256_cbc,
&libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */
&libssh2_crypt_method_aes192_cbc,
&libssh2_crypt_method_aes128_cbc,
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) */
#ifndef OPENSSL_NO_BLOWFISH
&libssh2_crypt_method_blowfish_cbc,
#endif /* ! OPENSSL_NO_BLOWFISH */
#ifndef OPENSSL_NO_RC4
&libssh2_crypt_method_arcfour,
#endif /* ! OPENSSL_NO_RC4 */
#ifndef OPENSSL_NO_CAST
&libssh2_crypt_method_cast128_cbc,
#endif /* ! OPENSSL_NO_CAST */
#ifndef OPENSSL_NO_DES
&libssh2_crypt_method_3des_cbc,
#endif /* ! OPENSSL_NO_DES */
#ifdef LIBSSH2_CRYPT_NONE
&libssh2_crypt_method_none,
#endif
NULL
};
/* Expose to kex.c */
LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void) {
return _libssh2_crypt_methods;
}

View File

@ -0,0 +1,546 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
/* Needed for struct iovec on some platforms */
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#ifndef OPENSSL_NO_RSA
/* ***********
* ssh-rsa *
*********** */
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **abstract);
/* {{{ libssh2_hostkey_method_ssh_rsa_init
* Initialize the server hostkey working area with e/n pair
*/
static int libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
{
RSA *rsactx;
unsigned char *s, *e, *n;
unsigned long len, e_len, n_len;
if (*abstract) {
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
s = hostkey_data;
len = libssh2_ntohu32(s); s += 4;
if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
return -1;
} s += 7;
e_len = libssh2_ntohu32(s); s += 4;
e = s; s += e_len;
n_len = libssh2_ntohu32(s); s += 4;
n = s; s += n_len;
rsactx = RSA_new();
rsactx->e = BN_new();
BN_bin2bn(e, e_len, rsactx->e);
rsactx->n = BN_new();
BN_bin2bn(n, n_len, rsactx->n);
*abstract = rsactx;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb
* TODO: Optionally call a passphrase callback specified by the calling program
*/
static int libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, int rwflag, char *passphrase)
{
int passphrase_len = strlen(passphrase);
if (passphrase_len > (size - 1)) {
passphrase_len = size - 1;
}
memcpy(buf, passphrase, passphrase_len);
buf[passphrase_len] = '\0';
return passphrase_len;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
* Load a Private Key from a PEM file
*/
static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
{
RSA *rsactx;
FILE *fp;
if (*abstract) {
libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
*abstract = NULL;
}
fp = fopen((char *)privkeyfile, "r");
if (!fp) {
return -1;
}
if (!EVP_get_cipherbyname("des")) {
/* If this cipher isn't loaded it's a pretty good indication that none are.
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
* Someone buy me an OpenSSL manual and I'll read up on it.
*/
OpenSSL_add_all_ciphers();
}
rsactx = PEM_read_RSAPrivateKey(fp, NULL, (int (*) (char *, int, int, void *))libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
if (!rsactx) {
fclose(fp);
return -1;
}
fclose(fp);
*abstract = rsactx;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
* Verify signature created by remote
*/
static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
const unsigned char *m, unsigned long m_len, void **abstract)
{
RSA *rsactx = (RSA*)(*abstract);
unsigned char hash[SHA_DIGEST_LENGTH];
int ret;
/* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
sig += 15; sig_len -= 15;
SHA1(m, m_len, hash);
ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, (unsigned char *)sig, sig_len, rsactx);
return (ret == 1) ? 0 : -1;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_sign
* Sign data to send to remote
*/
static int libssh2_hostkey_method_ssh_rsa_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
const unsigned char *buf, unsigned long buf_len, void **abstract)
{
RSA *rsactx = (RSA*)(*abstract);
int ret;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
char *sig;
int sig_len;
sig_len = RSA_size(rsactx);
sig = (char *) LIBSSH2_ALLOC(session, sig_len);
if (!sig) {
return -1;
}
SHA1_Init(&ctx);
SHA1_Update(&ctx, buf, buf_len);
SHA1_Final(hash, &ctx);
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, (unsigned char *) sig, (unsigned int *) &sig_len, rsactx);
if (!ret) {
LIBSSH2_FREE(session, sig);
return -1;
}
*signature = (unsigned char *) sig;
*signature_len = sig_len;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_signv
* Construct a signature from an array of vectors
*/
static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
unsigned long veccount, const struct iovec datavec[], void **abstract)
{
RSA *rsactx = (RSA*)(*abstract);
int ret, i;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
char *sig;
int sig_len;
sig_len = RSA_size(rsactx);
sig = (char *) LIBSSH2_ALLOC(session, sig_len);
if (!sig) {
return -1;
}
SHA1_Init(&ctx);
for(i = 0; i < (int) veccount; i++) {
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
}
SHA1_Final(hash, &ctx);
ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, (unsigned char *) sig, (unsigned int *) &sig_len, rsactx);
if (!ret) {
LIBSSH2_FREE(session, sig);
return -1;
}
*signature = (unsigned char *) sig;
*signature_len = sig_len;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_rsa_dtor
* Shutdown the hostkey
*/
static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION *session, void **abstract)
{
RSA *rsactx = (RSA*)(*abstract);
RSA_free(rsactx);
*abstract = NULL;
return 0;
}
/* }}} */
static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
"ssh-rsa",
MD5_DIGEST_LENGTH,
libssh2_hostkey_method_ssh_rsa_init,
libssh2_hostkey_method_ssh_rsa_initPEM,
libssh2_hostkey_method_ssh_rsa_sig_verify,
libssh2_hostkey_method_ssh_rsa_sign,
libssh2_hostkey_method_ssh_rsa_signv,
NULL, /* encrypt */
libssh2_hostkey_method_ssh_rsa_dtor,
};
#endif /* ! OPENSSL_NO_RSA */
#ifndef OPENSSL_NO_DSA
/* ***********
* ssh-dss *
*********** */
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **abstract);
/* {{{ libssh2_hostkey_method_ssh_dss_init
* Initialize the server hostkey working area with p/q/g/y set
*/
static int libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract)
{
DSA *dsactx;
unsigned char *p, *q, *g, *y, *s;
unsigned long p_len, q_len, g_len, y_len, len;
if (*abstract) {
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
s = hostkey_data;
len = libssh2_ntohu32(s); s += 4;
if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
return -1;
} s += 7;
p_len = libssh2_ntohu32(s); s += 4;
p = s; s += p_len;
q_len = libssh2_ntohu32(s); s += 4;
q = s; s += q_len;
g_len = libssh2_ntohu32(s); s += 4;
g = s; s += g_len;
y_len = libssh2_ntohu32(s); s += 4;
y = s; s += y_len;
dsactx = DSA_new();
dsactx->p = BN_new();
BN_bin2bn(p, p_len, dsactx->p);
dsactx->q = BN_new();
BN_bin2bn(q, q_len, dsactx->q);
dsactx->g = BN_new();
BN_bin2bn(g, g_len, dsactx->g);
dsactx->pub_key = BN_new();
BN_bin2bn(y, y_len, dsactx->pub_key);
*abstract = dsactx;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_dss_initPEM
* Load a Private Key from a PEM file
*/
static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract)
{
DSA *dsactx;
FILE *fp;
if (*abstract) {
libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
*abstract = NULL;
}
fp = fopen((char *) privkeyfile, "r");
if (!fp) {
return -1;
}
if (!EVP_get_cipherbyname("des")) {
/* If this cipher isn't loaded it's a pretty good indication that none are.
* I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#(
* Someone buy me an OpenSSL manual and I'll read up on it.
*/
OpenSSL_add_all_ciphers();
}
dsactx = PEM_read_DSAPrivateKey(fp, NULL, (int (*) (char *, int, int, void *))libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase);
if (!dsactx) {
fclose(fp);
return -1;
}
fclose(fp);
*abstract = dsactx;
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_dss_sign
* Verify signature created by remote
*/
static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len,
const unsigned char *m, unsigned long m_len, void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
unsigned char hash[SHA_DIGEST_LENGTH];
DSA_SIG dsasig;
int ret;
/* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
sig += 15; sig_len -= 15;
if (sig_len != 40) {
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid DSS signature length", 0);
return -1;
}
dsasig.r = BN_new();
BN_bin2bn(sig, 20, dsasig.r);
dsasig.s = BN_new();
BN_bin2bn(sig + 20, 20, dsasig.s);
SHA1(m, m_len, hash);
ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
return (ret == 1) ? 0 : -1;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_dss_sign
* Sign data to send to remote
*/
static int libssh2_hostkey_method_ssh_dss_sign(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
const unsigned char *buf, unsigned long buf_len, void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
*signature = (unsigned char *) LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
*signature_len = 2 * SHA_DIGEST_LENGTH;
if (!(*signature)) {
return -1;
}
SHA1_Init(&ctx);
SHA1_Update(&ctx, buf, buf_len);
SHA1_Final(hash, &ctx);
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!sig) {
LIBSSH2_FREE(session, *signature);
return -1;
}
BN_bn2bin(sig->r, *signature);
BN_bn2bin(sig->s, *signature + SHA_DIGEST_LENGTH);
DSA_SIG_free(sig);
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_dss_signv
* Construct a signature from an array of vectors
*/
static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len,
unsigned long veccount, const struct iovec datavec[], void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
DSA_SIG *sig;
unsigned char hash[SHA_DIGEST_LENGTH];
SHA_CTX ctx;
int r_len, s_len, rs_pad, i;
*signature = (unsigned char *) LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
*signature_len = 2 * SHA_DIGEST_LENGTH;
memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
if (!(*signature)) {
return -1;
}
SHA1_Init(&ctx);
for(i = 0; i < (int) veccount; i++) {
SHA1_Update(&ctx, datavec[i].iov_base, datavec[i].iov_len);
}
SHA1_Final(hash, &ctx);
sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
if (!sig) {
LIBSSH2_FREE(session, *signature);
return -1;
}
r_len = BN_num_bytes(sig->r);
s_len = BN_num_bytes(sig->s);
rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len);
if (rs_pad < 0) {
DSA_SIG_free(sig);
LIBSSH2_FREE(session, *signature);
return -1;
}
BN_bn2bin(sig->r, *signature + rs_pad);
BN_bn2bin(sig->s, *signature + rs_pad + r_len);
DSA_SIG_free(sig);
return 0;
}
/* }}} */
/* {{{ libssh2_hostkey_method_ssh_dss_dtor
* Shutdown the hostkey method
*/
static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION *session, void **abstract)
{
DSA *dsactx = (DSA*)(*abstract);
DSA_free(dsactx);
*abstract = NULL;
return 0;
}
/* }}} */
static LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
"ssh-dss",
MD5_DIGEST_LENGTH,
libssh2_hostkey_method_ssh_dss_init,
libssh2_hostkey_method_ssh_dss_initPEM,
libssh2_hostkey_method_ssh_dss_sig_verify,
libssh2_hostkey_method_ssh_dss_sign,
libssh2_hostkey_method_ssh_dss_signv,
NULL, /* encrypt */
libssh2_hostkey_method_ssh_dss_dtor,
};
#endif /* ! OPENSSL_NO_DSA */
static LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
#ifndef OPENSSL_NO_RSA
&libssh2_hostkey_method_ssh_rsa,
#endif /* ! OPENSSL_NO_RSA */
#ifndef OPENSSL_NO_DSA
&libssh2_hostkey_method_ssh_dss,
#endif /* ! OPENSSL_NO_DSA */
NULL
};
LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void)
{
return _libssh2_hostkey_methods;
}
/* {{{ libssh2_hostkey_hash
* Returns hash signature
* Returned buffer should NOT be freed
* Length of buffer is determined by hash type
* i.e. MD5 == 16, SHA1 == 20
*/
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type)
{
switch (hash_type) {
#ifndef OPENSSL_NO_MD5
case LIBSSH2_HOSTKEY_HASH_MD5:
return (char *) session->server_hostkey_md5;
break;
#endif /* ! OPENSSL_NO_MD5 */
#ifndef OPENSSL_NO_SHA
case LIBSSH2_HOSTKEY_HASH_SHA1:
return (char *) session->server_hostkey_sha1;
break;
#endif /* ! OPENSSL_NO_SHA */
default:
return NULL;
}
}
/* }}} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,400 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_H
#define LIBSSH2_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <string.h>
#include <sys/stat.h>
/* Allow alternate API prefix from CFLAGS or calling app */
#ifndef LIBSSH2_API
# ifdef LIBSSH2_WIN32
# ifdef LIBSSH2_LIBRARY
# define LIBSSH2_API __declspec(dllexport)
# else
# define LIBSSH2_API __declspec(dllimport)
# endif /* LIBSSH2_LIBRARY */
# else /* !LIBSSH2_WIN32 */
# define LIBSSH2_API
# endif /* LIBSSH2_WIN32 */
#endif /* LIBSSH2_API */
#if defined(LIBSSH2_DARWIN) || (defined(LIBSSH2_WIN32) && !defined(_MSC_VER))
# include <sys/uio.h>
#endif
#if defined(LIBSSH2_WIN32) && _MSC_VER < 1300
typedef unsigned __int64 libssh2_uint64_t;
typedef __int64 libssh2_int64_t;
#else
typedef unsigned long long libssh2_uint64_t;
typedef long long libssh2_int64_t;
#endif
#define LIBSSH2_VERSION "0.13"
#define LIBSSH2_APINO 200507211326
/* Part of every banner, user specified or not */
#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION
/* We *could* add a comment here if we so chose */
#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER
#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n"
/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */
#define LIBSSH2_DH_GEX_MINGROUP 1024
#define LIBSSH2_DH_GEX_OPTGROUP 1536
#define LIBSSH2_DH_GEX_MAXGROUP 2048
/* Defaults for pty requests */
#define LIBSSH2_TERM_WIDTH 80
#define LIBSSH2_TERM_HEIGHT 24
#define LIBSSH2_TERM_WIDTH_PX 0
#define LIBSSH2_TERM_HEIGHT_PX 0
/* 1/4 second */
#define LIBSSH2_SOCKET_POLL_UDELAY 250000
/* 0.25 * 120 == 30 seconds */
#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120
/* Maximum size to allow a payload to compress to, plays it safe by falling short of spec limits */
#define LIBSSH2_PACKET_MAXCOMP 32000
/* Maximum size to allow a payload to deccompress to, plays it safe by allowing more than spec requires */
#define LIBSSH2_PACKET_MAXDECOMP 40000
/* Maximum size for an inbound compressed payload, plays it safe by overshooting spec limits */
#define LIBSSH2_PACKET_MAXPAYLOAD 40000
/* Malloc callbacks */
#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract)
#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, void **abstract)
#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract)
typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT
{
char* text;
unsigned int length;
unsigned char echo;
} LIBSSH2_USERAUTH_KBDINT_PROMPT;
typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
{
char* text;
unsigned int length;
} LIBSSH2_USERAUTH_KBDINT_RESPONSE;
/* 'keyboard-interactive' authentication callback */
#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) void name_(const char* name, int name_len, const char* instruction, int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract)
/* Callbacks for special SSH packets */
#define LIBSSH2_IGNORE_FUNC(name) void name(LIBSSH2_SESSION *session, const char *message, int message_len, void **abstract)
#define LIBSSH2_DEBUG_FUNC(name) void name(LIBSSH2_SESSION *session, int always_display, const char *message, int message_len, const char *language, int language_len,void **abstract)
#define LIBSSH2_DISCONNECT_FUNC(name) void name(LIBSSH2_SESSION *session, int reason, const char *message, int message_len, const char *language, int language_len, void **abstract)
#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
#define LIBSSH2_MACERROR_FUNC(name) int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, void **abstract)
#define LIBSSH2_X11_OPEN_FUNC(name) void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, char *shost, int sport, void **abstract)
#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) void name(LIBSSH2_SESSION *session, void **session_abstract, LIBSSH2_CHANNEL *channel, void **channel_abstract)
/* libssh2_session_callback_set() constants */
#define LIBSSH2_CALLBACK_IGNORE 0
#define LIBSSH2_CALLBACK_DEBUG 1
#define LIBSSH2_CALLBACK_DISCONNECT 2
#define LIBSSH2_CALLBACK_MACERROR 3
#define LIBSSH2_CALLBACK_X11 4
/* libssh2_session_method_pref() constants */
#define LIBSSH2_METHOD_KEX 0
#define LIBSSH2_METHOD_HOSTKEY 1
#define LIBSSH2_METHOD_CRYPT_CS 2
#define LIBSSH2_METHOD_CRYPT_SC 3
#define LIBSSH2_METHOD_MAC_CS 4
#define LIBSSH2_METHOD_MAC_SC 5
#define LIBSSH2_METHOD_COMP_CS 6
#define LIBSSH2_METHOD_COMP_SC 7
#define LIBSSH2_METHOD_LANG_CS 8
#define LIBSSH2_METHOD_LANG_SC 9
/* session.flags bits */
#define LIBSSH2_FLAG_SIGPIPE 0x00000001
typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION;
typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL;
typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER;
typedef struct _LIBSSH2_POLLFD {
unsigned char type; /* LIBSSH2_POLLFD_* below */
union {
int socket; /* File descriptors -- examined with system select() call */
LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */
LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound connections waiting to be accepted? */
} fd;
unsigned long events; /* Requested Events */
unsigned long revents; /* Returned Events */
} LIBSSH2_POLLFD;
/* Poll FD Descriptor Types */
#define LIBSSH2_POLLFD_SOCKET 1
#define LIBSSH2_POLLFD_CHANNEL 2
#define LIBSSH2_POLLFD_LISTENER 3
/* Note: Win32 Doesn't actually have a poll() implementation, so some of these values are faked with select() data */
/* Poll FD events/revents -- Match sys/poll.h where possible */
#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or connection available -- All */
#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to be read -- Socket only */
#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to be read -- Channel only */
#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- Socket/Channel */
/* revents only */
#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */
#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */
#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */
#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket Only */
#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- Socket/Win32 */
#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */
#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */
/* Hash Types */
#define LIBSSH2_HOSTKEY_HASH_MD5 1
#define LIBSSH2_HOSTKEY_HASH_SHA1 2
/* Disconnect Codes (defined by SSH protocol) */
#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
#define SSH_DISCONNECT_PROTOCOL_ERROR 2
#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3
#define SSH_DISCONNECT_RESERVED 4
#define SSH_DISCONNECT_MAC_ERROR 5
#define SSH_DISCONNECT_COMPRESSION_ERROR 6
#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7
#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
#define SSH_DISCONNECT_CONNECTION_LOST 10
#define SSH_DISCONNECT_BY_APPLICATION 11
#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12
#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13
#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14
#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15
/* Error Codes (defined by libssh2) */
#define LIBSSH2_ERROR_SOCKET_NONE -1
#define LIBSSH2_ERROR_BANNER_NONE -2
#define LIBSSH2_ERROR_BANNER_SEND -3
#define LIBSSH2_ERROR_INVALID_MAC -4
#define LIBSSH2_ERROR_KEX_FAILURE -5
#define LIBSSH2_ERROR_ALLOC -6
#define LIBSSH2_ERROR_SOCKET_SEND -7
#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8
#define LIBSSH2_ERROR_TIMEOUT -9
#define LIBSSH2_ERROR_HOSTKEY_INIT -10
#define LIBSSH2_ERROR_HOSTKEY_SIGN -11
#define LIBSSH2_ERROR_DECRYPT -12
#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13
#define LIBSSH2_ERROR_PROTO -14
#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15
#define LIBSSH2_ERROR_FILE -16
#define LIBSSH2_ERROR_METHOD_NONE -17
#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED -18
#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19
#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20
#define LIBSSH2_ERROR_CHANNEL_FAILURE -21
#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22
#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23
#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24
#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25
#define LIBSSH2_ERROR_CHANNEL_CLOSED -26
#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27
#define LIBSSH2_ERROR_SCP_PROTOCOL -28
#define LIBSSH2_ERROR_ZLIB -29
#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30
#define LIBSSH2_ERROR_SFTP_PROTOCOL -31
#define LIBSSH2_ERROR_REQUEST_DENIED -32
#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33
#define LIBSSH2_ERROR_INVAL -34
#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35
#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36
/* Session API */
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract);
#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL)
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session);
LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback);
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner);
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket);
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang);
#define libssh2_session_disconnect(session, description) libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, (description), "")
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session);
LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, int hash_type);
LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, int method_type, const char *prefs);
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf);
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value);
/* Userauth API */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len);
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len, const char *password, int password_len, LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)));
#define libssh2_userauth_password(session, username, password) libssh2_userauth_password_ex((session), (username), strlen(username), (password), strlen(password), NULL)
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
const char *publickey, const char *privatekey,
const char *passphrase);
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
const char *publickey, const char *privatekey,
const char *passphrase,
const char *hostname, int hostname_len,
const char *local_username, int local_username_len);
#define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \
libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username))
/*
* response_callback is provided with filled by library prompts array,
* but client must allocate and fill individual responses. Responses
* array is already allocated. Responses data will be freed by libssh2
* after callback return, but before subsequent callback invokation.
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, const char *username, int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)));
#define libssh2_userauth_keyboard_interactive(session, username, response_callback) \
libssh2_userauth_keyboard_interactive_ex((session), (username), strlen(username), (response_callback))
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout);
/* Channel API */
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT 65536
#define LIBSSH2_CHANNEL_PACKET_DEFAULT 16384
#define LIBSSH2_CHANNEL_MINADJUST 1024
/* Extended Data Handling */
#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0
#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1
#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2
#define SSH_EXTENDED_DATA_STDERR 1
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, int channel_type_len, int window_size, int packet_size, const char *message, int message_len);
#define libssh2_channel_open_session(session) libssh2_channel_open_ex((session), "session", sizeof("session") - 1, LIBSSH2_CHANNEL_WINDOW_DEFAULT, LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, char *host, int port, char *shost, int sport);
#define libssh2_channel_direct_tcpip(session, host, port) libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22)
LIBSSH2_API LIBSSH2_LISTENER *libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, char *host, int port, int *bound_port, int queue_maxsize);
#define libssh2_channel_forward_listen(session, port) libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16)
LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener);
LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, char *varname, int varname_len, char *value, int value_len);
#define libssh2_channel_setenv(channel, varname, value) libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), strlen(value))
LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, char *term, int term_len, char *modes, int modes_len, int width, int height, int width_px, int height_px);
#define libssh2_channel_request_pty(channel, term) libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX)
LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, char *auth_proto, char *auth_cookie, int screen_number);
#define libssh2_channel_x11_req(channel, screen_number) libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number))
LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, const char *request, int request_len, const char *message, int message_len);
#define libssh2_channel_shell(channel) libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, NULL, 0)
#define libssh2_channel_exec(channel, command) libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, (command), strlen(command))
#define libssh2_channel_subsystem(channel, subsystem) libssh2_channel_process_startup((channel), "subsystem", sizeof("subsystem") - 1, (subsystem), strlen(subsystem))
LIBSSH2_API int libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, size_t buflen);
#define libssh2_channel_read(channel, buf, buflen) libssh2_channel_read_ex((channel), 0, (buf), (buflen))
#define libssh2_channel_read_stderr(channel, buf, buflen) libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended);
LIBSSH2_API unsigned long libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, unsigned long *read_avail, unsigned long *window_size_initial);
#define libssh2_channel_window_read(channel) libssh2_channel_window_read_ex((channel), NULL, NULL)
LIBSSH2_API unsigned long libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, unsigned long adjustment, unsigned char force);
LIBSSH2_API int libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, const char *buf, size_t buflen);
#define libssh2_channel_write(channel, buf, buflen) libssh2_channel_write_ex((channel), 0, (buf), (buflen))
#define libssh2_channel_write_stderr(channel, buf, buflen) libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen))
LIBSSH2_API unsigned long libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, unsigned long *window_size_initial);
#define libssh2_channel_window_write(channel) libssh2_channel_window_write_ex((channel), NULL)
LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, int blocking);
LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
/* libssh2_channel_ignore_extended_data() is defined below for BC with version 0.1
* Future uses should use libssh2_channel_handle_extended_data() directly
* if LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read (FIFO) from the standard data channel
*/
/* DEPRECATED */
#define libssh2_channel_ignore_extended_data(channel, ignore) libssh2_channel_handle_extended_data((channel), (ignore) ? LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL )
#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1
#define LIBSSH2_CHANNEL_FLUSH_ALL -2
LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int streamid);
#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0)
#define libssh2_channel_flush_stderr(channel) libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR)
LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel);
LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel);
LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb);
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime);
#define libssh2_scp_send(session, path, mode, size) libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0)
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, int *dest_len, char *src, int src_len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSSH2_H */

View File

@ -0,0 +1,38 @@
#ifndef WIN32
#define WIN32
#endif
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
/* same as WSABUF */
struct iovec {
u_long iov_len;
char *iov_base;
};
#define inline __inline
static inline int writev(int sock, struct iovec *iov, int nvecs)
{
DWORD ret;
if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) {
return ret;
}
return -1;
}
/* not really usleep, but safe for the way we use it in this lib */
static inline int usleep(int udelay)
{
Sleep(udelay / 1000);
return 0;
}
#define snprintf _snprintf
/* Compile in zlib support */
#define LIBSSH2_HAVE_ZLIB 1
/* Enable newer diffie-hellman-group-exchange-sha1 syntax */
#define LIBSSH2_DH_GEX_NEW 1

View File

@ -0,0 +1,479 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_PRIV_H
#define LIBSSH2_PRIV_H 1
#define LIBSSH2_LIBRARY
#include "libssh2_config.h"
#include "libssh2.h"
#ifndef WIN32
#include <sys/socket.h>
#endif
#include <openssl/evp.h>
#ifndef OPENSSL_NO_SHA
#include <openssl/sha.h>
#endif
#ifndef OPENSSL_NO_MD5
#include <openssl/md5.h>
#endif
#ifdef __hpux
# define inline
#endif
#define LIBSSH2_ALLOC(session, count) session->alloc((count), &(session)->abstract)
#define LIBSSH2_REALLOC(session, ptr, count) ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : session->alloc((count), &(session)->abstract))
#define LIBSSH2_FREE(session, ptr) session->free((ptr), &(session)->abstract)
#define LIBSSH2_IGNORE(session, data, datalen) session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract)
#define LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len) \
session->ssh_msg_disconnect((session), (always_display), (message), (message_len), (language), (language_len), &(session)->abstract)
#define LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len) \
session->ssh_msg_disconnect((session), (reason), (message), (message_len), (language), (language_len), &(session)->abstract)
#define LIBSSH2_MACERROR(session, data, datalen) session->macerror((session), (data), (datalen), &(session)->abstract)
#define LIBSSH2_X11_OPEN(channel, shost, sport) channel->session->x11(((channel)->session), (channel), (shost), (sport), (&(channel)->session->abstract))
#define LIBSSH2_CHANNEL_CLOSE(session, channel) channel->close_cb((session), &(session)->abstract, (channel), &(channel)->abstract)
typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD;
typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD;
typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD;
typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD;
typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET;
typedef struct _LIBSSH2_PACKET_BRIGADE LIBSSH2_PACKET_BRIGADE;
typedef struct _LIBSSH2_CHANNEL_BRIGADE LIBSSH2_CHANNEL_BRIGADE;
struct _LIBSSH2_PACKET {
unsigned char type;
/* Unencrypted Payload (no type byte, no padding, just the facts ma'am) */
unsigned char *data;
unsigned long data_len;
/* Where to start reading data from,
* used for channel data that's been partially consumed */
unsigned long data_head;
/* Can the message be confirmed? */
int mac;
LIBSSH2_PACKET_BRIGADE *brigade;
LIBSSH2_PACKET *next, *prev;
};
struct _LIBSSH2_PACKET_BRIGADE {
LIBSSH2_PACKET *head, *tail;
};
typedef struct _libssh2_channel_data {
/* Identifier */
unsigned long id;
/* Limits and restrictions */
unsigned long window_size_initial, window_size, packet_size;
/* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */
char close, eof, extended_data_ignore_mode;
} libssh2_channel_data;
struct _LIBSSH2_CHANNEL {
unsigned char *channel_type;
unsigned channel_type_len;
int blocking;
/* channel's program exit status */
int exit_status;
libssh2_channel_data local, remote;
unsigned long adjust_queue; /* Amount of bytes to be refunded to receive window (but not yet sent) */
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *next, *prev;
void *abstract;
LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb));
};
struct _LIBSSH2_CHANNEL_BRIGADE {
LIBSSH2_CHANNEL *head, *tail;
};
struct _LIBSSH2_LISTENER {
LIBSSH2_SESSION *session;
char *host;
int port;
LIBSSH2_CHANNEL *queue;
int queue_size;
int queue_maxsize;
LIBSSH2_LISTENER *prev, *next;
};
typedef struct _libssh2_endpoint_data {
unsigned char *banner;
unsigned char *kexinit;
unsigned long kexinit_len;
LIBSSH2_CRYPT_METHOD *crypt;
void *crypt_abstract;
LIBSSH2_MAC_METHOD *mac;
unsigned long seqno;
void *mac_abstract;
LIBSSH2_COMP_METHOD *comp;
void *comp_abstract;
/* Method Preferences -- NULL yields "load order" */
char *crypt_prefs;
char *mac_prefs;
char *comp_prefs;
char *lang_prefs;
} libssh2_endpoint_data;
struct _LIBSSH2_SESSION {
/* Memory management callbacks */
void *abstract;
LIBSSH2_ALLOC_FUNC((*alloc));
LIBSSH2_REALLOC_FUNC((*realloc));
LIBSSH2_FREE_FUNC((*free));
/* Other callbacks */
LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore));
LIBSSH2_DEBUG_FUNC((*ssh_msg_debug));
LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect));
LIBSSH2_MACERROR_FUNC((*macerror));
LIBSSH2_X11_OPEN_FUNC((*x11));
/* Method preferences -- NULL yields "load order" */
char *kex_prefs;
char *hostkey_prefs;
int state;
int flags;
/* Agreed Key Exchange Method */
LIBSSH2_KEX_METHOD *kex;
unsigned char *session_id;
unsigned long session_id_len;
/* Server's public key */
LIBSSH2_HOSTKEY_METHOD *hostkey;
void *server_hostkey_abstract;
/* Either set with libssh2_session_hostkey() (for server mode)
* Or read from server in (eg) KEXDH_INIT (for client mode)
*/
unsigned char *server_hostkey;
unsigned long server_hostkey_len;
#ifndef OPENSSL_NO_MD5
unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH];
#endif /* ! OPENSSL_NO_MD5 */
#ifndef OPENSSL_NO_SHA
unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH];
#endif
/* (remote as source of data -- packet_read ) */
libssh2_endpoint_data remote;
/* (local as source of data -- packet_write ) */
libssh2_endpoint_data local;
/* Inbound Data buffer -- Sometimes the packet that comes in isn't the packet we're ready for */
LIBSSH2_PACKET_BRIGADE packets;
/* Active connection channels */
LIBSSH2_CHANNEL_BRIGADE channels;
unsigned long next_channel;
LIBSSH2_LISTENER *listeners;
/* Actual I/O socket */
int socket_fd;
int socket_block;
int socket_state;
/* Error tracking */
char *err_msg;
unsigned long err_msglen;
int err_should_free;
int err_code;
};
/* session.state bits */
#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
#define LIBSSH2_STATE_NEWKEYS 0x00000002
#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
/* session.flag helpers */
#ifdef MSG_NOSIGNAL
#define LIBSSH2_SOCKET_SEND_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
#define LIBSSH2_SOCKET_RECV_FLAGS(session) (((session)->flags & LIBSSH2_FLAG_SIGPIPE) ? 0 : MSG_NOSIGNAL)
#else
/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */
#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0
#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0
#endif
/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional methods via .so/.dll */
struct _LIBSSH2_KEX_METHOD {
char *name;
/* Key exchange, populates session->* and returns 0 on success, non-0 on error */
int (*exchange_keys)(LIBSSH2_SESSION *session);
long flags;
};
struct _LIBSSH2_HOSTKEY_METHOD {
char *name;
unsigned long hash_len;
int (*init)(LIBSSH2_SESSION *session, unsigned char *hostkey_data, unsigned long hostkey_data_len, void **abstract);
int (*initPEM)(LIBSSH2_SESSION *session, unsigned const char *privkeyfile, unsigned const char *passphrase, void **abstract);
int (*sig_verify)(LIBSSH2_SESSION *session, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len, void **abstract);
int (*sign)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, const unsigned char *data, unsigned long data_len, void **abstract);
int (*signv)(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract);
int (*encrypt)(LIBSSH2_SESSION *session, unsigned char **dst, unsigned long *dst_len, const unsigned char *src, unsigned long src_len, void **abstract);
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
};
/* When FLAG_EVP is set, crypt contains a pointer to an EVP_CIPHER generator and init and dtor are ignored
* Yes, I know it's a hack.
*/
#define LIBSSH2_CRYPT_METHOD_FLAG_EVP 0x0001
struct _LIBSSH2_CRYPT_METHOD {
char *name;
int blocksize;
/* iv and key sizes (-1 for variable length) */
int iv_len;
int secret_len;
long flags;
int (*init)(LIBSSH2_SESSION *session, unsigned char *iv, int *free_iv, unsigned char *secret, int *free_secret, int encrypt, void **abstract);
int (*crypt)(LIBSSH2_SESSION *session, unsigned char *block, void **abstract);
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
};
struct _LIBSSH2_COMP_METHOD {
char *name;
int (*init)(LIBSSH2_SESSION *session, int compress, void **abstract);
int (*comp)(LIBSSH2_SESSION *session, int compress, unsigned char **dest, unsigned long *dest_len, unsigned long payload_limit, int *free_dest,
const unsigned char *src, unsigned long src_len, void **abstract);
int (*dtor)(LIBSSH2_SESSION *session, int compress, void **abstract);
};
struct _LIBSSH2_MAC_METHOD {
char *name;
/* The length of a given MAC packet */
int mac_len;
/* integrity key length */
int key_len;
/* Message Authentication Code Hashing algo */
int (*init)(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract);
int (*hash)(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno, const unsigned char *packet, unsigned long packet_len, const unsigned char *addtl, unsigned long addtl_len, void **abstract);
int (*dtor)(LIBSSH2_SESSION *session, void **abstract);
};
#if defined(LIBSSH2_DEBUG_TRANSPORT) || defined(LIBSSH2_DEBUG_KEX) || defined(LIBSSH2_DEBUG_USERAUTH) || defined(LIBSSH2_DEBUG_CONNECTION) || defined(LIBSSH2_DEBUG_SCP) || defined(LIBSSH2_DEBUG_SFTP) || defined(LIBSSH2_DEBUG_ERRORS)
#define LIBSSH2_DEBUG_ENABLED
/* Internal debugging contexts -- Used with --enable-debug-* */
#define LIBSSH2_DBG_TRANS 1
#define LIBSSH2_DBG_KEX 2
#define LIBSSH2_DBG_AUTH 3
#define LIBSSH2_DBG_CONN 4
#define LIBSSH2_DBG_SCP 5
#define LIBSSH2_DBG_SFTP 6
#define LIBSSH2_DBG_ERROR 7
#define LIBSSH2_DBG_PUBLICKEY 8
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...);
#endif /* LIBSSH2_DEBUG_ENABLED */
#ifdef LIBSSH2_DEBUG_ERRORS
#define libssh2_error(session, errcode, errmsg, should_free) \
{ \
if (session->err_msg && session->err_should_free) { \
LIBSSH2_FREE(session, session->err_msg); \
} \
session->err_msg = errmsg; \
session->err_msglen = strlen(errmsg); \
session->err_should_free = should_free; \
session->err_code = errcode; \
_libssh2_debug(session, LIBSSH2_DBG_ERROR, "%d - %s", session->err_code, session->err_msg); \
}
#else /* ! LIBSSH2_DEBUG_ERRORS */
#define libssh2_error(session, errcode, errmsg, should_free) \
{ \
if (session->err_msg && session->err_should_free) { \
LIBSSH2_FREE(session, session->err_msg); \
} \
session->err_msg = errmsg; \
session->err_msglen = strlen(errmsg); \
session->err_should_free = should_free; \
session->err_code = errcode; \
}
#endif /* LIBSSH2_DEBUG_ENABLED */
#define LIBSSH2_SOCKET_UNKNOWN 1
#define LIBSSH2_SOCKET_CONNECTED 0
#define LIBSSH2_SOCKET_DISCONNECTED -1
/* Initial packet state, prior to MAC check */
#define LIBSSH2_MAC_UNCONFIRMED 1
/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */
#define LIBSSH2_MAC_CONFIRMED 0
/* Something very bad is going on */
#define LIBSSH2_MAC_INVALID -1
/* SSH Packet Types -- Defined by internet draft */
/* Transport Layer */
#define SSH_MSG_DISCONNECT 1
#define SSH_MSG_IGNORE 2
#define SSH_MSG_UNIMPLEMENTED 3
#define SSH_MSG_DEBUG 4
#define SSH_MSG_SERVICE_REQUEST 5
#define SSH_MSG_SERVICE_ACCEPT 6
#define SSH_MSG_KEXINIT 20
#define SSH_MSG_NEWKEYS 21
/* diffie-hellman-group1-sha1 */
#define SSH_MSG_KEXDH_INIT 30
#define SSH_MSG_KEXDH_REPLY 31
/* diffie-hellman-group-exchange-sha1 */
#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30
#define SSH_MSG_KEX_DH_GEX_REQUEST 34
#define SSH_MSG_KEX_DH_GEX_GROUP 31
#define SSH_MSG_KEX_DH_GEX_INIT 32
#define SSH_MSG_KEX_DH_GEX_REPLY 33
/* User Authentication */
#define SSH_MSG_USERAUTH_REQUEST 50
#define SSH_MSG_USERAUTH_FAILURE 51
#define SSH_MSG_USERAUTH_SUCCESS 52
#define SSH_MSG_USERAUTH_BANNER 53
/* "public key" method */
#define SSH_MSG_USERAUTH_PK_OK 60
/* "password" method */
#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
/* "keyboard-interactive" method */
#define SSH_MSG_USERAUTH_INFO_REQUEST 60
#define SSH_MSG_USERAUTH_INFO_RESPONSE 61
/* Channels */
#define SSH_MSG_GLOBAL_REQUEST 80
#define SSH_MSG_REQUEST_SUCCESS 81
#define SSH_MSG_REQUEST_FAILURE 82
#define SSH_MSG_CHANNEL_OPEN 90
#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91
#define SSH_MSG_CHANNEL_OPEN_FAILURE 92
#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93
#define SSH_MSG_CHANNEL_DATA 94
#define SSH_MSG_CHANNEL_EXTENDED_DATA 95
#define SSH_MSG_CHANNEL_EOF 96
#define SSH_MSG_CHANNEL_CLOSE 97
#define SSH_MSG_CHANNEL_REQUEST 98
#define SSH_MSG_CHANNEL_SUCCESS 99
#define SSH_MSG_CHANNEL_FAILURE 100
void libssh2_session_shutdown(LIBSSH2_SESSION *session);
unsigned long libssh2_ntohu32(const unsigned char *buf);
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf);
void libssh2_htonu32(unsigned char *buf, unsigned long val);
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val);
int libssh2_packet_read(LIBSSH2_SESSION *session, int block);
int libssh2_packet_ask_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
#define libssh2_packet_ask(session, packet_type, data, data_len, poll_socket) \
libssh2_packet_ask_ex((session), (packet_type), (data), (data_len), 0, NULL, 0, (poll_socket))
int libssh2_packet_askv_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len, int poll_socket);
#define libssh2_packet_askv(session, packet_types, data, data_len, poll_socket) \
libssh2_packet_askv_ex((session), (packet_types), (data), (data_len), 0, NULL, 0, (poll_socket))
int libssh2_packet_require_ex(LIBSSH2_SESSION *session, unsigned char packet_type, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
#define libssh2_packet_require(session, packet_type, data, data_len) \
libssh2_packet_require_ex((session), (packet_type), (data), (data_len), 0, NULL, 0)
int libssh2_packet_requirev_ex(LIBSSH2_SESSION *session, unsigned char *packet_types, unsigned char **data, unsigned long *data_len, unsigned long match_ofs, const unsigned char *match_buf, unsigned long match_len);
#define libssh2_packet_requirev(session, packet_types, data, data_len) \
libssh2_packet_requirev_ex((session), (packet_types), (data), (data_len), 0, NULL, 0)
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len);
int libssh2_kex_exchange(LIBSSH2_SESSION *session, int reexchange);
unsigned long libssh2_channel_nextid(LIBSSH2_SESSION *session);
LIBSSH2_CHANNEL *libssh2_channel_locate(LIBSSH2_SESSION *session, unsigned long channel_id);
/* Let crypt.c/hostkey.c/comp.c/mac.c expose their method structs */
LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
LIBSSH2_COMP_METHOD **libssh2_comp_methods(void);
LIBSSH2_MAC_METHOD **libssh2_mac_methods(void);
/* Language API doesn't exist yet. Just act like we've agreed on a language */
#define libssh2_kex_agree_lang(session, endpoint, str, str_len) 0
#endif /* LIBSSH2_H */

View File

@ -0,0 +1,101 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/* Note: This include file is only needed for using the
* publickey SUBSYSTEM which is not the same as publickey
* authentication. For authentication you only need libssh2.h
*
* For more information on the publickey subsystem,
* refer to IETF draft: secsh-publickey
*/
#ifndef LIBSSH2_PUBLICKEY_H
#define LIBSSH2_PUBLICKEY_H 1
typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY;
typedef struct _libssh2_publickey_attribute {
char *name;
unsigned long name_len;
char *value;
unsigned long value_len;
char mandatory;
} libssh2_publickey_attribute;
typedef struct _libssh2_publickey_list {
unsigned char *packet; /* For freeing */
unsigned char *name;
unsigned long name_len;
unsigned char *blob;
unsigned long blob_len;
unsigned long num_attrs;
libssh2_publickey_attribute *attrs; /* free me */
} libssh2_publickey_list;
/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */
#define libssh2_publickey_attribute(name, value, mandatory) { (name), strlen(name), (value), strlen(value), (mandatory) },
#define libssh2_publickey_attribute_fast(name, value, mandatory) { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
#ifdef __cplusplus
extern "C" {
#endif
/* Publickey Subsystem */
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
const unsigned char *blob, unsigned long blob_len, char overwrite,
unsigned long num_attrs, libssh2_publickey_attribute attrs[]);
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, num_attrs, attrs) \
libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), (overwrite), (num_attrs), (attrs))
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
const unsigned char *blob, unsigned long blob_len);
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list);
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list);
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ndef: LIBSSH2_PUBLICKEY_H */

View File

@ -0,0 +1,198 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#ifndef LIBSSH2_SFTP_H
#define LIBSSH2_SFTP_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Note: Version 6 was documented at the time of writing
* However it was marked as "DO NOT IMPLEMENT" due to pending changes
*
* Let's start with Version 3 (The version found in OpenSSH) and go from there
*/
#define LIBSSH2_SFTP_VERSION 3
#define LIBSSH2_SFTP_PACKET_MAXLEN 40000
typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP;
typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE;
typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES;
/* Flags for open_ex() */
#define LIBSSH2_SFTP_OPENFILE 0
#define LIBSSH2_SFTP_OPENDIR 1
/* Flags for rename_ex() */
#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001
#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002
#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004
/* Flags for stat_ex() */
#define LIBSSH2_SFTP_STAT 0
#define LIBSSH2_SFTP_LSTAT 1
#define LIBSSH2_SFTP_SETSTAT 2
/* Flags for symlink_ex() */
#define LIBSSH2_SFTP_SYMLINK 0
#define LIBSSH2_SFTP_READLINK 1
#define LIBSSH2_SFTP_REALPATH 2
/* SFTP attribute flag bits */
#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001
#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002
#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004
#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008
#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000
struct _LIBSSH2_SFTP_ATTRIBUTES {
/* If flags & ATTR_* bit is set, then the value in this struct will be meaningful
* Otherwise it should be ignored
*/
unsigned long flags;
libssh2_uint64_t filesize;
unsigned long uid, gid;
unsigned long permissions;
unsigned long atime, mtime;
};
/* SFTP filetypes */
#define LIBSSH2_SFTP_TYPE_REGULAR 1
#define LIBSSH2_SFTP_TYPE_DIRECTORY 2
#define LIBSSH2_SFTP_TYPE_SYMLINK 3
#define LIBSSH2_SFTP_TYPE_SPECIAL 4
#define LIBSSH2_SFTP_TYPE_UNKNOWN 5
#define LIBSSH2_SFTP_TYPE_SOCKET 6
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8
#define LIBSSH2_SFTP_TYPE_FIFO 9
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
* Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
#define LIBSSH2_FXF_READ 0x00000001
#define LIBSSH2_FXF_WRITE 0x00000002
#define LIBSSH2_FXF_APPEND 0x00000004
#define LIBSSH2_FXF_CREAT 0x00000008
#define LIBSSH2_FXF_TRUNC 0x00000010
#define LIBSSH2_FXF_EXCL 0x00000020
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
#define LIBSSH2_FX_OK 0
#define LIBSSH2_FX_EOF 1
#define LIBSSH2_FX_NO_SUCH_FILE 2
#define LIBSSH2_FX_PERMISSION_DENIED 3
#define LIBSSH2_FX_FAILURE 4
#define LIBSSH2_FX_BAD_MESSAGE 5
#define LIBSSH2_FX_NO_CONNECTION 6
#define LIBSSH2_FX_CONNECTION_LOST 7
#define LIBSSH2_FX_OP_UNSUPPORTED 8
#define LIBSSH2_FX_INVALID_HANDLE 9
#define LIBSSH2_FX_NO_SUCH_PATH 10
#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11
#define LIBSSH2_FX_WRITE_PROTECT 12
#define LIBSSH2_FX_NO_MEDIA 13
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14
#define LIBSSH2_FX_QUOTA_EXCEEDED 15
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16
#define LIBSSH2_FX_LOCK_CONFlICT 17
#define LIBSSH2_FX_DIR_NOT_EMPTY 18
#define LIBSSH2_FX_NOT_A_DIRECTORY 19
#define LIBSSH2_FX_INVALID_FILENAME 20
#define LIBSSH2_FX_LINK_LOOP 21
/* SFTP API */
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
/* File / Directory Ops */
LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len, unsigned long flags, long mode, int open_type);
#define libssh2_sftp_open(sftp, filename, flags, mode) libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), (mode), LIBSSH2_SFTP_OPENFILE)
#define libssh2_sftp_opendir(sftp, path) libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, LIBSSH2_SFTP_OPENDIR)
LIBSSH2_API size_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen);
LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs);
LIBSSH2_API size_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, size_t count);
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek((handle), 0)
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat);
#define libssh2_sftp_fstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 0)
#define libssh2_sftp_fsetstat(handle, attrs) libssh2_sftp_fstat_ex((handle), (attrs), 1)
/* Miscellaneous Ops */
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, char *source_filename, int srouce_filename_len,
char *dest_filename, int dest_filename_len,
long flags);
#define libssh2_sftp_rename(sftp, sourcefile, destfile) libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), (destfile), strlen(destfile), \
LIBSSH2_SFTP_RENAME_OVERWRITE | LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE)
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, char *filename, int filename_len);
#define libssh2_sftp_unlink(sftp, filename) libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, long mode);
#define libssh2_sftp_mkdir(sftp, path, mode) libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, char *path, int path_len);
#define libssh2_sftp_rmdir(sftp, path) libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, char *path, int path_len, int stat_type, LIBSSH2_SFTP_ATTRIBUTES *attrs);
#define libssh2_sftp_stat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, (attrs))
#define libssh2_sftp_lstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, (attrs))
#define libssh2_sftp_setstat(sftp, path, attrs) libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, (attrs))
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, int path_len, char *target, int target_len, int link_type);
#define libssh2_sftp_symlink(sftp, orig, linkpath) libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
#define libssh2_sftp_readlink(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_READLINK)
#define libssh2_sftp_realpath(sftp, path, target, maxlen) libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), LIBSSH2_SFTP_REALPATH)
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LIBSSH2_SFTP_H */

View File

@ -0,0 +1,271 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <openssl/hmac.h>
#ifdef LIBSSH2_MAC_NONE
/* {{{ libssh2_mac_none_MAC
* Minimalist MAC: No MAC
*/
static int libssh2_mac_none_MAC(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_none = {
"none",
0,
0,
NULL,
libssh2_mac_none_MAC,
NULL
};
#endif /* LIBSSH2_MAC_NONE */
/* {{{ libssh2_mac_method_common_init
* Initialize simple mac methods
*/
static int libssh2_mac_method_common_init(LIBSSH2_SESSION *session, unsigned char *key, int *free_key, void **abstract)
{
*abstract = key;
*free_key = 0;
return 0;
}
/* }}} */
/* {{{ libssh2_mac_method_common_dtor
* Cleanup simple mac methods
*/
static int libssh2_mac_method_common_dtor(LIBSSH2_SESSION *session, void **abstract)
{
if (*abstract) {
LIBSSH2_FREE(session, *abstract);
}
*abstract = NULL;
return 0;
}
/* }}} */
/* {{{ libssh2_mac_method_hmac_sha1_hash
* Calculate hash using full sha1 value
*/
static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
HMAC_CTX ctx;
unsigned char seqno_buf[4];
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, 20, EVP_sha1());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
HMAC_Update(&ctx, addtl, addtl_len);
}
HMAC_Final(&ctx, buf, NULL);
HMAC_cleanup(&ctx);
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1 = {
"hmac-sha1",
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_hash,
libssh2_mac_method_common_dtor,
};
/* {{{ libssh2_mac_method_hmac_sha1_96_hash
* Calculate hash using first 96 bits of sha1 value
*/
static int libssh2_mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
char temp[SHA_DIGEST_LENGTH];
libssh2_mac_method_hmac_sha1_hash(session, (unsigned char *) temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
memcpy(buf, temp, 96 / 8);
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_sha1_96 = {
"hmac-sha1-96",
12,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_sha1_96_hash,
libssh2_mac_method_common_dtor,
};
/* {{{ libssh2_mac_method_hmac_md5_hash
* Calculate hash using full md5 value
*/
static int libssh2_mac_method_hmac_md5_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
HMAC_CTX ctx;
unsigned char seqno_buf[4];
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, 16, EVP_md5());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
HMAC_Update(&ctx, addtl, addtl_len);
}
HMAC_Final(&ctx, buf, NULL);
HMAC_cleanup(&ctx);
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5 = {
"hmac-md5",
16,
16,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_hash,
libssh2_mac_method_common_dtor,
};
/* {{{ libssh2_mac_method_hmac_md5_96_hash
* Calculate hash using first 96 bits of md5 value
*/
static int libssh2_mac_method_hmac_md5_96_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
char temp[MD5_DIGEST_LENGTH];
libssh2_mac_method_hmac_md5_hash(session, (unsigned char *)temp, seqno, packet, packet_len, addtl, addtl_len, abstract);
memcpy(buf, temp, 96 / 8);
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_md5_96 = {
"hmac-md5-96",
12,
16,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_md5_96_hash,
libssh2_mac_method_common_dtor,
};
#ifndef OPENSSL_NO_RIPEMD
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
* Calculate hash using ripemd160 value
*/
static int libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
const unsigned char *packet, unsigned long packet_len,
const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
HMAC_CTX ctx;
unsigned char seqno_buf[4];
libssh2_htonu32(seqno_buf, seqno);
HMAC_Init(&ctx, *abstract, 20, EVP_ripemd160());
HMAC_Update(&ctx, seqno_buf, 4);
HMAC_Update(&ctx, packet, packet_len);
if (addtl && addtl_len) {
HMAC_Update(&ctx, addtl, addtl_len);
}
HMAC_Final(&ctx, buf, NULL);
HMAC_cleanup(&ctx);
return 0;
}
/* }}} */
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160 = {
"hmac-ripemd160",
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor,
};
static LIBSSH2_MAC_METHOD libssh2_mac_method_hmac_ripemd160_openssh_com = {
"hmac-ripemd160@openssh.com",
20,
20,
libssh2_mac_method_common_init,
libssh2_mac_method_hmac_ripemd160_hash,
libssh2_mac_method_common_dtor,
};
#endif /* ! OPENSSL_NO_RIPEMD */
static LIBSSH2_MAC_METHOD *_libssh2_mac_methods[] = {
&libssh2_mac_method_hmac_sha1,
&libssh2_mac_method_hmac_sha1_96,
&libssh2_mac_method_hmac_md5,
&libssh2_mac_method_hmac_md5_96,
#ifndef OPENSSL_NO_RIPEMD
&libssh2_mac_method_hmac_ripemd160,
&libssh2_mac_method_hmac_ripemd160_openssh_com,
#endif /* ! OPENSSL_NO_RIPEMD */
#ifdef LIBSSH2_MAC_NONE
&libssh2_mac_method_none,
#endif /* LIBSSH2_MAC_NONE */
NULL
};
LIBSSH2_MAC_METHOD **libssh2_mac_methods(void) {
return _libssh2_mac_methods;
}

View File

@ -0,0 +1,210 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
/* {{{ libssh2_ntohu32
*/
unsigned long libssh2_ntohu32(const unsigned char *buf)
{
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
}
/* }}} */
/* {{{ libssh2_ntohu64
* Note: Some 32-bit platforms have issues with bitops on long longs
* Work around this by doing expensive (but safer) arithmetic ops with optimization defying parentheses
*/
libssh2_uint64_t libssh2_ntohu64(const unsigned char *buf)
{
unsigned long msl, lsl;
msl = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
lsl = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
return ((msl * 65536) * 65536) + lsl;
}
/* }}} */
/* {{{ libssh2_htonu32
*/
void libssh2_htonu32(unsigned char *buf, unsigned long value)
{
buf[0] = (value >> 24) & 0xFF;
buf[1] = (value >> 16) & 0xFF;
buf[2] = (value >> 8) & 0xFF;
buf[3] = value & 0xFF;
}
/* }}} */
/* {{{ libssh2_htonu64
*/
void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t value)
{
unsigned long msl = (value / 65536) / 65536;
buf[0] = (msl >> 24) & 0xFF;
buf[1] = (msl >> 16) & 0xFF;
buf[2] = (msl >> 8) & 0xFF;
buf[3] = msl & 0xFF;
buf[4] = (value >> 24) & 0xFF;
buf[5] = (value >> 16) & 0xFF;
buf[6] = (value >> 8) & 0xFF;
buf[7] = value & 0xFF;
}
/* }}} */
/* Base64 Conversion */
/* {{{ */
static const char libssh2_base64_table[] =
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
};
static const char libssh2_base64_pad = '=';
static const short libssh2_base64_reverse_table[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
/* }}} */
/* {{{ libssh2_base64_decode
* Decode a base64 chunk and store it into a newly alloc'd buffer
*/
LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, int *datalen,
char *src, int src_len)
{
unsigned char *s, *d;
short v;
int i = 0, len = 0;
d = (unsigned char *) LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
*data = (char *) d;
if (!d) {
return -1;
}
for(s = (unsigned char *)src; ((char*)s) < (src + src_len); s++) {
if ((v = libssh2_base64_reverse_table[*s]) < 0) continue;
switch (i % 4) {
case 0:
d[len] = v << 2;
break;
case 1:
d[len++] |= v >> 4;
d[len] = v << 4;
break;
case 2:
d[len++] |= v >> 2;
d[len] = v << 6;
break;
case 3:
d[len++] |= v;
break;
}
i++;
}
if ((i % 4) == 1) {
/* Invalid -- We have a byte which belongs exclusively to a partial octet */
LIBSSH2_FREE(session, *data);
return -1;
}
*datalen = len;
return 0;
}
/* }}} */
#ifdef LIBSSH2_DEBUG_ENABLED
/* {{{ _libssh2_debug
* Internal debug logging facility
* Just writes to stderr until a good reason comes up to support anything else
*/
void _libssh2_debug(LIBSSH2_SESSION *session, int context, const char *format, ...)
{
char buffer[1536];
int len;
va_list vargs;
FILE *file; /* TODO: Change to fstream */
char *contexts[9] = { "Unknown",
"Transport",
"Key Exhange",
"Userauth",
"Connection",
"scp",
"SFTP Subsystem",
"Failure Event",
"Publickey Subsystem",
};
if (context < 1 || context > 8) {
context = 0;
}
len = snprintf(buffer, 1535, "[libssh2] %s: ", contexts[context]);
va_start(vargs, format);
len += vsnprintf(buffer + len, 1535 - len, format, vargs);
buffer[len] = '\0';
va_end(vargs);
fprintf (stderr, "%s\n", buffer);
}
/* }}} */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,728 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include "libssh2_publickey.h"
struct _LIBSSH2_PUBLICKEY {
LIBSSH2_CHANNEL *channel;
unsigned long version;
};
#define LIBSSH2_PUBLICKEY_VERSION 2
/* Numericised response codes -- Not IETF standard, just a local representation */
#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0
#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1
#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2
typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST {
int code;
char *name;
int name_len;
} LIBSSH2_PUBLICKEY_CODE_LIST;
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_response_codes[] = {
{ LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1 },
{ LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1 },
{ LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", sizeof("publickey") - 1 },
{ 0, NULL, 0 }
};
/* PUBLICKEY status codes -- IETF defined */
#define LIBSSH2_PUBLICKEY_SUCCESS 0
#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1
#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2
#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3
#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4
#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5
#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6
#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7
#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8
#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8
static LIBSSH2_PUBLICKEY_CODE_LIST libssh2_publickey_status_codes[] = {
{ LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1 },
{ LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", sizeof("access denied") - 1 },
{ LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", sizeof("storage exceeded") - 1 },
{ LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", sizeof("version not supported") - 1 },
{ LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", sizeof("key not found") - 1 },
{ LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", sizeof("key not supported") - 1 },
{ LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", sizeof("key already present") - 1 },
{ LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", sizeof("general failure") - 1 },
{ LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", sizeof("request not supported") - 1 },
{ 0, NULL, 0 }
};
/* {{{ libssh2_publickey_status_error
* Format an error message from a status code
*/
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_START "Publickey Subsystem Error: \""
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_MID "\" Server Resports: \""
#define LIBSSH2_PUBLICKEY_STATUS_TEXT_END "\""
static void libssh2_publickey_status_error(LIBSSH2_PUBLICKEY *pkey, LIBSSH2_SESSION *session, int status, unsigned char *message, int message_len)
{
char *status_text;
int status_text_len;
char *m, *s;
int m_len;
/* GENERAL_FAILURE got remapped between version 1 and 2 */
if (status == 6 && pkey && pkey->version == 1) {
status = 7;
}
if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) {
status_text = "unknown";
status_text_len = sizeof("unknown") - 1;
} else {
status_text = libssh2_publickey_status_codes[status].name;
status_text_len = libssh2_publickey_status_codes[status].name_len;
}
m_len = (sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1) + status_text_len +
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1) + message_len +
(sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
m = (char *)LIBSSH2_ALLOC(session, m_len + 1);
if (!m) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for status message", 0);
return;
}
s = m;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_START, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_START) - 1;
memcpy(s, status_text, status_text_len); s += status_text_len;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_MID, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_MID) - 1;
memcpy(s, message, message_len); s += message_len;
memcpy(s, LIBSSH2_PUBLICKEY_STATUS_TEXT_END, sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END) - 1);
s += sizeof(LIBSSH2_PUBLICKEY_STATUS_TEXT_END);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, m, 1);
}
/* }}} */
/* {{{ libssh2_publickey_packet_receive
* Read a packet from the subsystem
*/
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char buffer[4];
unsigned long packet_len;
unsigned char *packet;
if (libssh2_channel_read(channel,(char *) buffer, 4) != 4) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
return -1;
}
packet_len = libssh2_ntohu32(buffer);
packet = (unsigned char *)LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
return -1;
}
if (libssh2_channel_read(channel, (char *)packet, packet_len) != (int)packet_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
*data = packet;
*data_len = packet_len;
return 0;
}
/* }}} */
/* {{{ libssh2_publickey_response_id
* Translate a string response name to a numeric code
* Data will be incremented by 4 + response_len on success only
*/
static int libssh2_publickey_response_id(unsigned char **pdata, int data_len)
{
unsigned long response_len;
unsigned char *data = *pdata;
LIBSSH2_PUBLICKEY_CODE_LIST *codes = libssh2_publickey_response_codes;
if (data_len < 4) {
/* Malformed response */
return -1;
}
response_len = libssh2_ntohu32(data); data += 4; data_len -= 4;
if (data_len < (int) response_len) {
/* Malformed response */
return -1;
}
while (codes->name) {
if (codes->name_len == (int)response_len &&
strncmp((char *)codes->name, (char *)data, response_len) == 0) {
*pdata = data + response_len;
return codes->code;
}
codes++;
}
return -1;
}
/* }}} */
/* {{{ libssh2_publickey_response_success
* Generic helper routine to wait for success response and nothing else
*/
static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
{
LIBSSH2_SESSION *session = pkey->channel->session;
unsigned char *data, *s;
unsigned long data_len, response;
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
return -1;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
LIBSSH2_FREE(session, data);
return -1;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error, or processing complete */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
LIBSSH2_FREE(session, data);
return -1;
}
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
LIBSSH2_FREE(session, data);
return 0;
}
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
LIBSSH2_FREE(session, data);
return -1;
}
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
data = NULL;
}
}
/* never reached, but include `return` to silence compiler warnings */
return -1;
}
/* }}} */
/* *****************
* Publickey API *
***************** */
/* {{{ libssh2_publickey_init
* Startup the publickey subsystem
*/
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
{
LIBSSH2_PUBLICKEY *pkey = NULL;
LIBSSH2_CHANNEL *channel = NULL;
unsigned char buffer[19];
/* packet_len(4) +
version_len(4) +
"version"(7) +
version_num(4) */
unsigned char *s, *data = NULL;
unsigned long data_len;
int response;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
#endif
channel = libssh2_channel_open_session(session);
if (!channel) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
goto err_exit;
}
if (libssh2_channel_subsystem(channel, "publickey")) {
libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
goto err_exit;
}
libssh2_channel_set_blocking(channel, 1);
libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);
pkey = (LIBSSH2_PUBLICKEY *)LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
if (!pkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
goto err_exit;
}
pkey->channel = channel;
pkey->version = 0;
s = buffer;
libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); s += 4;
libssh2_htonu32(s, sizeof("version") - 1); s += 4;
memcpy(s, "version", sizeof("version") - 1); s += sizeof("version") - 1;
libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); s += 4;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
#endif
if ((s - buffer) != libssh2_channel_write(channel, (char *)buffer, (s - buffer))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
goto err_exit;
}
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
goto err_exit;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
goto err_exit;
}
libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
/* What we want */
pkey->version = libssh2_ntohu32(s);
if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
#endif
pkey->version = LIBSSH2_PUBLICKEY_VERSION;
}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
#endif
LIBSSH2_FREE(session, data);
return pkey;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
data = NULL;
}
}
/* Never reached except by direct goto */
err_exit:
if (channel) {
libssh2_channel_close(channel);
}
if (pkey) {
LIBSSH2_FREE(session, pkey);
}
if (data) {
LIBSSH2_FREE(session, data);
}
return NULL;
}
/* }}} */
/* {{{ libssh2_publickey_add_ex
* Add a new public key entry
*/
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
const unsigned char *blob, unsigned long blob_len, char overwrite,
unsigned long num_attrs, libssh2_publickey_attribute attrs[])
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char *packet = NULL, *s;
unsigned long i, packet_len = 19 + name_len + blob_len;
unsigned char *comment = NULL;
unsigned long comment_len = 0;
/* packet_len(4) +
add_len(4) +
"add"(3) +
name_len(4) +
{name}
blob_len(4) +
{blob} */
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
#endif
if (pkey->version == 1) {
for(i = 0; i < num_attrs; i++) {
/* Search for a comment attribute */
if (attrs[i].name_len == (sizeof("comment") - 1) &&
strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
comment = (unsigned char *)attrs[i].value;
comment_len = attrs[i].value_len;
break;
}
}
packet_len += 4 + comment_len;
} else {
packet_len += 5; /* overwrite(1) + attribute_count(4) */
for(i = 0; i < num_attrs; i++) {
packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
/* name_len(4) + value_len(4) + mandatory(1) */
}
}
packet = (unsigned char *)LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
return -1;
}
s = packet;
libssh2_htonu32(s, packet_len - 4); s += 4;
libssh2_htonu32(s, sizeof("add") - 1); s += 4;
memcpy(s, "add", sizeof("add") - 1); s += sizeof("add") - 1;
if (pkey->version == 1) {
libssh2_htonu32(s, comment_len); s += 4;
if (comment) {
memcpy(s, comment, comment_len); s += comment_len;
}
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
} else {
/* Version == 2 */
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
*(s++) = overwrite ? 0xFF : 0;
libssh2_htonu32(s, num_attrs); s += 4;
for(i = 0; i < num_attrs; i++) {
libssh2_htonu32(s, attrs[i].name_len); s += 4;
memcpy(s, attrs[i].name, attrs[i].name_len); s += attrs[i].name_len;
libssh2_htonu32(s, attrs[i].value_len); s += 4;
memcpy(s, attrs[i].value, attrs[i].value_len); s += attrs[i].value_len;
*(s++) = attrs[i].mandatory ? 0xFF : 0;
}
}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld", name, blob_len, num_attrs);
#endif
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
packet = NULL;
return libssh2_publickey_response_success(pkey);
}
/* }}} */
/* {{{ libssh2_publickey_remove_ex
* Remove an existing publickey so that authentication can no longer be performed using it
*/
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
const unsigned char *blob, unsigned long blob_len)
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
unsigned char *s, *packet = NULL;
unsigned long packet_len = 22 + name_len + blob_len;
/* packet_len(4) +
remove_len(4) +
"remove"(6) +
name_len(4) +
{name}
blob_len(4) +
{blob} */
packet = (unsigned char *)LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
return -1;
}
s = packet;
libssh2_htonu32(s, packet_len - 4); s += 4;
libssh2_htonu32(s, sizeof("remove") - 1); s += 4;
memcpy(s, "remove", sizeof("remove") - 1); s += sizeof("remove") - 1;
libssh2_htonu32(s, name_len); s += 4;
memcpy(s, name, name_len); s += name_len;
libssh2_htonu32(s, blob_len); s += 4;
memcpy(s, blob, blob_len); s += blob_len;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
#endif
if ((s - packet) != libssh2_channel_write(channel, (char *)packet, (s - packet))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
packet = NULL;
return libssh2_publickey_response_success(pkey);
}
/* }}} */
/* {{{ libssh2_publickey_list_fetch
* Fetch a list of supported public key from a server
*/
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
{
LIBSSH2_CHANNEL *channel = pkey->channel;
LIBSSH2_SESSION *session = channel->session;
libssh2_publickey_list *list = NULL;
unsigned char *s, buffer[12], *data = NULL;
unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i, response;
/* packet_len(4) +
list_len(4) +
"list"(4) */
s = buffer;
libssh2_htonu32(s, buffer_len - 4); s += 4;
libssh2_htonu32(s, sizeof("list") - 1); s += 4;
memcpy(s, "list", sizeof("list") - 1); s += sizeof("list") - 1;
#ifdef LIBSSH2_DEBUG_PUBLICKEY
_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
#endif
if ((s - buffer) != libssh2_channel_write(channel, (char *)buffer, (s - buffer))) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
return -1;
}
while (1) {
if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
goto err_exit;
}
s = data;
if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
goto err_exit;
}
switch (response) {
case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
/* Error, or processing complete */
{
unsigned long status, descr_len, lang_len;
unsigned char *descr, *lang;
status = libssh2_ntohu32(s); s += 4;
descr_len = libssh2_ntohu32(s); s += 4;
descr = s; s += descr_len;
lang_len = libssh2_ntohu32(s); s += 4;
lang = s; s += lang_len;
if (s > data + data_len) {
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
goto err_exit;
}
if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
LIBSSH2_FREE(session, data);
*pkey_list = list;
*num_keys = keys;
return 0;
}
libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
goto err_exit;
}
case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
/* What we want */
if (keys >= max_keys) {
/* Grow the key list if necessary */
max_keys += 8;
list = (libssh2_publickey_list *)LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
if (!list) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
goto err_exit;
}
}
if (pkey->version == 1) {
unsigned long comment_len;
comment_len = libssh2_ntohu32(s); s += 4;
if (comment_len) {
list[keys].num_attrs = 1;
list[keys].attrs = (libssh2_publickey_attribute *)LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
if (!list[keys].attrs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
goto err_exit;
}
list[keys].attrs[0].name = "comment";
list[keys].attrs[0].name_len = sizeof("comment") - 1;
list[keys].attrs[0].value = (char *)s;
list[keys].attrs[0].value_len = comment_len;
list[keys].attrs[0].mandatory = 0;
s += comment_len;
} else {
list[keys].num_attrs = 0;
list[keys].attrs = NULL;
}
list[keys].name_len = libssh2_ntohu32(s); s += 4;
list[keys].name = s; s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
list[keys].blob = s; s += list[keys].blob_len;
} else {
/* Version == 2 */
list[keys].name_len = libssh2_ntohu32(s); s += 4;
list[keys].name = s; s += list[keys].name_len;
list[keys].blob_len = libssh2_ntohu32(s); s += 4;
list[keys].blob = s; s += list[keys].blob_len;
list[keys].num_attrs = libssh2_ntohu32(s); s += 4;
if (list[keys].num_attrs) {
list[keys].attrs = (libssh2_publickey_attribute *)LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
if (!list[keys].attrs) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
goto err_exit;
}
for(i = 0; i < list[keys].num_attrs; i++) {
list[keys].attrs[i].name_len = libssh2_ntohu32(s); s += 4;
list[keys].attrs[i].name = (char *)s; s += list[keys].attrs[i].name_len;
list[keys].attrs[i].value_len = libssh2_ntohu32(s); s += 4;
list[keys].attrs[i].value = (char *)s; s += list[keys].attrs[i].value_len;
list[keys].attrs[i].mandatory = 0; /* actually an ignored value */
}
} else {
list[keys].attrs = NULL;
}
}
list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
keys++;
list[keys].packet = NULL; /* Terminate the list */
data = NULL;
break;
default:
/* Unknown/Unexpected */
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
LIBSSH2_FREE(session, data);
}
}
/* Only reached via explicit goto */
err_exit:
if (data) {
LIBSSH2_FREE(session, data);
}
if (list) {
libssh2_publickey_list_free(pkey, list);
}
return -1;
}
/* }}} */
/* {{{ libssh2_publickey_list_free
* Free a previously fetched list of public keys
*/
LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, libssh2_publickey_list *pkey_list)
{
LIBSSH2_SESSION *session = pkey->channel->session;
libssh2_publickey_list *p = pkey_list;
while (p->packet) {
if (p->attrs) {
LIBSSH2_FREE(session, p->attrs);
}
LIBSSH2_FREE(session, p->packet);
p++;
}
LIBSSH2_FREE(session, pkey_list);
}
/* }}} */
/* {{{ libssh2_publickey_shutdown
* Shutdown the publickey subsystem
*/
LIBSSH2_API void libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey)
{
LIBSSH2_SESSION *session = pkey->channel->session;
libssh2_channel_free(pkey->channel);
LIBSSH2_FREE(session, pkey);
}
/* }}} */

View File

@ -0,0 +1,437 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <errno.h>
#include <stdlib.h>
#define LIBSSH2_SCP_RESPONSE_BUFLEN 256
/* {{{ libssh2_scp_recv
* Open a channel and request a remote file via SCP
*/
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat *sb)
{
int path_len = strlen(path);
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
unsigned long command_len = path_len + sizeof("scp -f "), response_len;
LIBSSH2_CHANNEL *channel;
long mode = 0, size = 0, mtime = 0, atime = 0;
if (sb) {
command_len++;
}
command = (unsigned char *) LIBSSH2_ALLOC(session, command_len);
if (!command) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0);
return NULL;
}
if (sb) {
memcpy(command, "scp -pf ", sizeof("scp -pf ") - 1);
memcpy(command + sizeof("scp -pf ") - 1, path, path_len);
} else {
memcpy(command, "scp -f ", sizeof("scp -f ") - 1);
memcpy(command + sizeof("scp -f ") - 1, path, path_len);
}
command[command_len - 1] = '\0';
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP receive");
#endif
/* Allocate a channel */
if ((channel = libssh2_channel_open_session(session)) == NULL) {
LIBSSH2_FREE(session, command);
return NULL;
}
/* Use blocking I/O for negotiation phase */
libssh2_channel_set_blocking(channel, 1);
/* Request SCP for the desired file */
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, (char *)command, command_len)) {
LIBSSH2_FREE(session, command);
libssh2_channel_free(channel);
return NULL;
}
LIBSSH2_FREE(session, command);
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
#endif
/* SCP ACK */
response[0] = '\0';
if (libssh2_channel_write(channel, (char *)response, 1) != 1) {
libssh2_channel_free(channel);
return NULL;
}
/* Parse SCP response */
response_len = 0;
while (sb && (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN)) {
unsigned char *s, *p;
if (libssh2_channel_read(channel, (char *)response + response_len, 1) <= 0) {
/* Timeout, give up */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
libssh2_channel_free(channel);
return NULL;
}
response_len++;
if (response[0] != 'T') {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response, missing Time data", 0);
libssh2_channel_free(channel);
return NULL;
}
if ((response_len > 1) &&
((response[response_len-1] < '0') || (response[response_len-1] > '9')) &&
(response[response_len-1] != ' ') &&
(response[response_len-1] != '\r') &&
(response[response_len-1] != '\n')) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
libssh2_channel_free(channel);
return NULL;
}
if ((response_len < 9) || (response[response_len-1] != '\n')) {
if (response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
/* You had your chance */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Way too short to be an SCP response, or not done yet, short circuit */
continue;
}
/* We're guaranteed not to go under response_len == 0 by the logic above */
while ((response[response_len-1] == '\r') || (response[response_len-1] == '\n')) response_len--;
response[response_len] = '\0';
if (response_len < 8) {
/* EOL came too soon */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
libssh2_channel_free(channel);
return NULL;
}
s = response + 1;
p = (unsigned char *) strchr((char *)s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime", 0);
libssh2_channel_free(channel);
return NULL;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
mtime = strtol((char *)s, NULL, 10);
if (errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mtime", 0);
libssh2_channel_free(channel);
return NULL;
}
s = (unsigned char *)strchr((char *)p, ' ');
if (!s || ((s - p) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mtime.usec", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Ignore mtime.usec */
s++;
p = (unsigned char *)strchr((char *)s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0);
libssh2_channel_free(channel);
return NULL;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
atime = strtol((char *)s, NULL, 10);
if (errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid atime", 0);
libssh2_channel_free(channel);
return NULL;
}
/* SCP ACK */
response[0] = '\0';
if (libssh2_channel_write(channel, (char *)response, 1) != 1) {
libssh2_channel_free(channel);
return NULL;
}
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mtime = %ld, atime = %ld", mtime, atime);
#endif
/* We *should* check that atime.usec is valid, but why let that stop use? */
break;
}
response_len = 0;
while (response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
char *s, *p, *e = NULL;
if (libssh2_channel_read(channel, (char *)response + response_len, 1) <= 0) {
/* Timeout, give up */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Timed out waiting for SCP response", 0);
libssh2_channel_free(channel);
return NULL;
}
response_len++;
if (response[0] != 'C') {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server", 0);
libssh2_channel_free(channel);
return NULL;
}
if ((response_len > 1) &&
(response[response_len-1] != '\r') &&
(response[response_len-1] != '\n') &&
((response[response_len-1] < 32) || (response[response_len-1] > 126))) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid data in SCP response", 0);
libssh2_channel_free(channel);
return NULL;
}
if ((response_len < 7) || (response[response_len-1] != '\n')) {
if (response_len == LIBSSH2_SCP_RESPONSE_BUFLEN) {
/* You had your chance */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Unterminated response from SCP server", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Way too short to be an SCP response, or not done yet, short circuit */
continue;
}
/* We're guaranteed not to go under response_len == 0 by the logic above */
while ((response[response_len-1] == '\r') || (response[response_len-1] == '\n')) response_len--;
response[response_len] = '\0';
if (response_len < 6) {
/* EOL came too soon */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short", 0);
libssh2_channel_free(channel);
return NULL;
}
s = (char *)response + 1;
p = strchr(s, ' ');
if (!p || ((p - s) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, malformed mode", 0);
libssh2_channel_free(channel);
return NULL;
}
*(p++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
mode = strtol(s, &e, 8);
if ((e && *e) || errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid mode", 0);
libssh2_channel_free(channel);
return NULL;
}
s = strchr(p, ' ');
if (!s || ((s - p) <= 0)) {
/* No spaces or space in the wrong spot */
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, too short or malformed", 0);
libssh2_channel_free(channel);
return NULL;
}
*(s++) = '\0';
/* Make sure we don't get fooled by leftover values */
errno = 0;
size = strtol(p, &e, 10);
if ((e && *e) || errno) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid response from SCP server, invalid size", 0);
libssh2_channel_free(channel);
return NULL;
}
/* SCP ACK */
response[0] = '\0';
if (libssh2_channel_write(channel, (char *)response, 1) != 1) {
libssh2_channel_free(channel);
return NULL;
}
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "mod = 0%lo size = %ld", mode, size);
#endif
/* We *should* check that basename is valid, but why let that stop us? */
break;
}
if (sb) {
memset(sb, 0, sizeof(struct stat));
sb->st_mtime = mtime;
sb->st_atime = atime;
sb->st_size = size;
sb->st_mode = mode;
}
/* Revert to non-blocking and let the data BEGIN! */
libssh2_channel_set_blocking(channel, 0);
return channel;
}
/* }}} */
/* {{{ libssh2_scp_send_ex
* Send a file using SCP
*/
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, size_t size, long mtime, long atime)
{
int path_len = strlen(path);
unsigned char *command, response[LIBSSH2_SCP_RESPONSE_BUFLEN];
unsigned long response_len, command_len = path_len + sizeof("scp -t ");
unsigned const char *base;
LIBSSH2_CHANNEL *channel;
if (mtime || atime) {
command_len++;
}
command = (unsigned char *)LIBSSH2_ALLOC(session, command_len);
if (!command) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a command buffer for scp session", 0);
return NULL;
}
if (mtime || atime) {
memcpy(command, "scp -pt ", sizeof("scp -pt ") - 1);
memcpy(command + sizeof("scp -pt ") - 1, path, path_len);
} else {
memcpy(command, "scp -t ", sizeof("scp -t ") - 1);
memcpy(command + sizeof("scp -t ") - 1, path, path_len);
}
command[command_len - 1] = '\0';
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Opening channel for SCP send");
#endif
/* Allocate a channel */
if ((channel = libssh2_channel_open_session(session)) == NULL) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, command);
return NULL;
}
/* Use blocking I/O for negotiation phase */
libssh2_channel_set_blocking(channel, 1);
/* Request SCP for the desired file */
if (libssh2_channel_process_startup(channel, "exec", sizeof("exec") - 1, (char *)command, command_len)) {
/* previous call set libssh2_session_last_error(), pass it through */
LIBSSH2_FREE(session, command);
libssh2_channel_free(channel);
return NULL;
}
LIBSSH2_FREE(session, command);
/* Wait for ACK */
if ((libssh2_channel_read(channel, (char *)response, 1) <= 0) || (response[0] != 0)) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Send mtime and atime to be used for file */
if (mtime || atime) {
response_len = snprintf((char *)response, LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime, atime);
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
#endif
if (libssh2_channel_write(channel, (char *)response, response_len) != (int)response_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send time data for SCP file", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Wait for ACK */
if ((libssh2_channel_read(channel, (char *)response, 1) <= 0) || (response[0] != 0)) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
libssh2_channel_free(channel);
return NULL;
}
}
/* Send mode, size, and basename */
base = (unsigned char *)strrchr((char *)path, '/');
if (base) {
base++;
} else {
base = (unsigned char *)path;
}
response_len = snprintf((char *)response, LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode, (unsigned long)size, base);
#ifdef LIBSSH2_DEBUG_SCP
_libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s", response);
#endif
if (libssh2_channel_write(channel, (char *)response, response_len) != (int)response_len) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send core file data for SCP file", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Wait for ACK */
if ((libssh2_channel_read(channel, (char *)response, 1) <= 0) || (response[0] != 0)) {
libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, "Invalid ACK response from remote", 0);
libssh2_channel_free(channel);
return NULL;
}
/* Ready to start, switch to non-blocking and let calling app send file */
libssh2_channel_set_blocking(channel, 0);
return channel;
}
/* }}} */

View File

@ -0,0 +1,966 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#include <math.h>
#endif
#ifdef HAVE_POLL
# include <sys/poll.h>
#else
# ifdef HAVE_SELECT
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# else
# include <sys/time.h>
# include <sys/types.h>
# endif
# endif
#endif
/* {{{ libssh2_default_alloc
*/
static LIBSSH2_ALLOC_FUNC(libssh2_default_alloc)
{
return malloc(count);
}
/* }}} */
/* {{{ libssh2_default_free
*/
static LIBSSH2_FREE_FUNC(libssh2_default_free)
{
free(ptr);
}
/* }}} */
/* {{{ libssh2_default_realloc
*/
static LIBSSH2_REALLOC_FUNC(libssh2_default_realloc)
{
return realloc(ptr, count);
}
/* }}} */
/* {{{ libssh2_banner_receive
* Wait for a hello from the remote host
* Allocate a buffer and store the banner in session->remote.banner
* Returns: 0 on success, 1 on failure
*/
static int libssh2_banner_receive(LIBSSH2_SESSION *session)
{
char banner[256];
int banner_len = 0;
while ((banner_len < (int) sizeof(banner)) &&
((banner_len == 0) || (banner[banner_len-1] != '\n'))) {
char c = '\0';
int ret;
ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
if ((ret < 0) && (ret != EAGAIN)) {
/* Some kinda error, but don't break for non-blocking issues */
return 1;
}
if (ret <= 0) continue;
if (c == '\0') {
/* NULLs are not allowed in SSH banners */
return 1;
}
banner[banner_len++] = c;
}
while (banner_len &&
((banner[banner_len-1] == '\n') || (banner[banner_len-1] == '\r'))) {
banner_len--;
}
if (!banner_len) return 1;
session->remote.banner = (unsigned char *) LIBSSH2_ALLOC(session, banner_len + 1);
memcpy(session->remote.banner, banner, banner_len);
session->remote.banner[banner_len] = '\0';
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Received Banner: %s", session->remote.banner);
#endif
return 0;
}
/* }}} */
/* {{{ libssh2_banner_send
* Send the default banner, or the one set via libssh2_setopt_string
*/
static int libssh2_banner_send(LIBSSH2_SESSION *session)
{
char *banner = LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF;
int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1;
if (session->local.banner) {
/* setopt_string will have given us our \r\n characters */
banner_len = strlen((char *) session->local.banner);
banner = (char *) session->local.banner;
}
#ifdef LIBSSH2_DEBUG_TRANSPORT
{
/* Hack and slash to avoid sending CRLF in debug output */
char banner_dup[256];
if (banner_len < 256) {
memcpy(banner_dup, banner, banner_len - 2);
banner_dup[banner_len - 2] = '\0';
} else {
memcpy(banner_dup, banner, 255);
banner[255] = '\0';
}
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending Banner: %s", banner_dup);
}
#endif
return (send(session->socket_fd, banner, banner_len, LIBSSH2_SOCKET_SEND_FLAGS(session)) == banner_len) ? 0 : 1;
}
/* }}} */
/* {{{ libssh2_banner_set
* Set the local banner
*/
LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, const char *banner)
{
int banner_len = banner ? strlen(banner) : 0;
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
session->local.banner = NULL;
}
if (!banner_len) {
return 0;
}
session->local.banner = (unsigned char *) LIBSSH2_ALLOC(session, banner_len + 3);
if (!session->local.banner) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for local banner", 0);
return -1;
}
memcpy(session->local.banner, banner, banner_len);
#ifdef LIBSSH2_DEBUG_TRANSPORT
session->local.banner[banner_len] = '\0';
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting local Banner: %s", session->local.banner);
#endif
session->local.banner[banner_len++] = '\r';
session->local.banner[banner_len++] = '\n';
session->local.banner[banner_len++] = '\0';
return 0;
}
/* }}} */
/* {{{ proto libssh2_session_init
* Allocate and initialize a libssh2 session structure
* Allows for malloc callbacks in case the calling program has its own memory manager
* It's allowable (but unadvisable) to define some but not all of the malloc callbacks
* An additional pointer value may be optionally passed to be sent to the callbacks (so they know who's asking)
*/
LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(
LIBSSH2_ALLOC_FUNC((*my_alloc)),
LIBSSH2_FREE_FUNC((*my_free)),
LIBSSH2_REALLOC_FUNC((*my_realloc)),
void *abstract)
{
LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc;
LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free;
LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc;
LIBSSH2_SESSION *session;
if (my_alloc) local_alloc = my_alloc;
if (my_free) local_free = my_free;
if (my_realloc) local_realloc = my_realloc;
session = (LIBSSH2_SESSION *) local_alloc(sizeof(LIBSSH2_SESSION), (void **) abstract);
memset(session, 0, sizeof(LIBSSH2_SESSION));
session->alloc = local_alloc;
session->free = local_free;
session->realloc = local_realloc;
session->abstract = abstract;
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "New session resource allocated");
#endif
return session;
}
/* }}} */
/* {{{ libssh2_session_callback_set
* Set (or reset) a callback function
* Returns the prior address
*/
LIBSSH2_API void* libssh2_session_callback_set(LIBSSH2_SESSION *session, int cbtype, void *callback)
{
void *oldcb;
switch (cbtype) {
case LIBSSH2_CALLBACK_IGNORE:
oldcb = (void *) session->ssh_msg_ignore;
session->ssh_msg_ignore = (void (*) (LIBSSH2_SESSION*, const char *, int, void **))callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_DEBUG:
oldcb = (void *) session->ssh_msg_debug;
session->ssh_msg_debug = (void (*) (LIBSSH2_SESSION*, int, const char *, int, const char *, int, void **))callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_DISCONNECT:
oldcb = (void *) session->ssh_msg_disconnect;
session->ssh_msg_disconnect = (void (*) (LIBSSH2_SESSION*, int, const char *, int, const char *, int, void **))callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_MACERROR:
oldcb = (void *) session->macerror;
session->macerror = (int (*) (LIBSSH2_SESSION*, const char *, int, void **))callback;
return oldcb;
break;
case LIBSSH2_CALLBACK_X11:
oldcb = (void *) session->x11;
session->x11 = (void (*) (LIBSSH2_SESSION*, LIBSSH2_CHANNEL*, char*, int, void **) )callback;
return oldcb;
break;
}
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Setting Callback %d", cbtype);
#endif
return NULL;
}
/* }}} */
/* {{{ proto libssh2_session_startup
* session: LIBSSH2_SESSION struct allocated and owned by the calling program
* Returns: 0 on success, or non-zero on failure
* Any memory allocated by libssh2 will use alloc/realloc/free callbacks in session
* socket *must* be populated with an opened socket
*/
LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int socket)
{
unsigned char *data;
unsigned long data_len;
unsigned char service[sizeof("ssh-userauth") + 5 - 1];
unsigned long service_length;
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "session_startup for socket %d", socket);
#endif
if (socket <= 0) {
/* Did we forget something? */
libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE, "No socket provided", 0);
return LIBSSH2_ERROR_SOCKET_NONE;
}
session->socket_fd = socket;
/* TODO: Liveness check */
if (libssh2_banner_send(session)) {
/* Unable to send banner? */
libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND, "Error sending banner to remote host", 0);
return LIBSSH2_ERROR_BANNER_SEND;
}
if (libssh2_banner_receive(session)) {
/* Unable to receive banner from remote */
libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE, "Timeout waiting for banner", 0);
return LIBSSH2_ERROR_BANNER_NONE;
}
if (libssh2_kex_exchange(session, 0)) {
libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE, "Unable to exchange encryption keys", 0);
return LIBSSH2_ERROR_KEX_FAILURE;
}
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Requesting userauth service");
#endif
/* Request the userauth service */
service[0] = SSH_MSG_SERVICE_REQUEST;
libssh2_htonu32(service + 1, sizeof("ssh-userauth") - 1);
memcpy(service + 5, "ssh-userauth", sizeof("ssh-userauth") - 1);
if (libssh2_packet_write(session, service, sizeof("ssh-userauth") + 5 - 1)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to ask for ssh-userauth service", 0);
return LIBSSH2_ERROR_SOCKET_SEND;
}
if (libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, &data, &data_len)) {
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
}
service_length = libssh2_ntohu32(data + 1);
if ((service_length != (sizeof("ssh-userauth") - 1)) ||
strncmp((char *)"ssh-userauth", (char *)data + 5, service_length)) {
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_PROTO, "Invalid response received from server", 0);
return LIBSSH2_ERROR_PROTO;
}
LIBSSH2_FREE(session, data);
return 0;
}
/* }}} */
/* {{{ proto libssh2_session_free
* Frees the memory allocated to the session
* Also closes and frees any channels attached to this session
*/
LIBSSH2_API void libssh2_session_free(LIBSSH2_SESSION *session)
{
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Freeing session resource", session->remote.banner);
#endif
while (session->channels.head) {
LIBSSH2_CHANNEL *tmp = session->channels.head;
libssh2_channel_free(session->channels.head);
if (tmp == session->channels.head) {
/* channel_free couldn't do it's job, perform a messy cleanup */
tmp = session->channels.head;
/* unlink */
session->channels.head = tmp->next;
/* free */
LIBSSH2_FREE(session, tmp);
/* reverse linking isn't important here, we're killing the structure */
}
}
while (session->listeners) {
libssh2_channel_forward_cancel(session->listeners);
}
if (session->state & LIBSSH2_STATE_NEWKEYS) {
/* hostkey */
if (session->hostkey && session->hostkey->dtor) {
session->hostkey->dtor(session, &session->server_hostkey_abstract);
}
/* Client to Server */
/* crypt */
if (session->local.crypt) {
if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->local.crypt_abstract) {
LIBSSH2_FREE(session, session->local.crypt_abstract);
session->local.crypt_abstract = NULL;
}
} else if (session->local.crypt->dtor) {
session->local.crypt->dtor(session, &session->local.crypt_abstract);
}
}
/* comp */
if (session->local.comp && session->local.comp->dtor) {
session->local.comp->dtor(session, 1, &session->local.comp_abstract);
}
/* mac */
if (session->local.mac && session->local.mac->dtor) {
session->local.mac->dtor(session, &session->local.mac_abstract);
}
/* Server to Client */
/* crypt */
if (session->remote.crypt) {
if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
if (session->remote.crypt_abstract) {
LIBSSH2_FREE(session, session->remote.crypt_abstract);
session->remote.crypt_abstract = NULL;
}
} else if (session->remote.crypt->dtor) {
session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
}
}
/* comp */
if (session->remote.comp && session->remote.comp->dtor) {
session->remote.comp->dtor(session, 0, &session->remote.comp_abstract);
}
/* mac */
if (session->remote.mac && session->remote.mac->dtor) {
session->remote.mac->dtor(session, &session->remote.mac_abstract);
}
/* session_id */
if (session->session_id) {
LIBSSH2_FREE(session, session->session_id);
}
}
/* Free banner(s) */
if (session->remote.banner) {
LIBSSH2_FREE(session, session->remote.banner);
}
if (session->local.banner) {
LIBSSH2_FREE(session, session->local.banner);
}
/* Free preference(s) */
if (session->kex_prefs) {
LIBSSH2_FREE(session, session->kex_prefs);
}
if (session->hostkey_prefs) {
LIBSSH2_FREE(session, session->hostkey_prefs);
}
if (session->local.crypt_prefs) {
LIBSSH2_FREE(session, session->local.crypt_prefs);
}
if (session->local.mac_prefs) {
LIBSSH2_FREE(session, session->local.mac_prefs);
}
if (session->local.comp_prefs) {
LIBSSH2_FREE(session, session->local.comp_prefs);
}
if (session->local.lang_prefs) {
LIBSSH2_FREE(session, session->local.lang_prefs);
}
if (session->remote.crypt_prefs) {
LIBSSH2_FREE(session, session->remote.crypt_prefs);
}
if (session->remote.mac_prefs) {
LIBSSH2_FREE(session, session->remote.mac_prefs);
}
if (session->remote.comp_prefs) {
LIBSSH2_FREE(session, session->remote.comp_prefs);
}
if (session->remote.lang_prefs) {
LIBSSH2_FREE(session, session->remote.lang_prefs);
}
/* Cleanup any remaining packets */
while (session->packets.head) {
LIBSSH2_PACKET *tmp = session->packets.head;
/* unlink */
session->packets.head = tmp->next;
/* free */
LIBSSH2_FREE(session, tmp->data);
LIBSSH2_FREE(session, tmp);
}
LIBSSH2_FREE(session, session);
}
/* }}} */
/* {{{ libssh2_session_disconnect_ex
*/
LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, const char *description, const char *lang)
{
unsigned char *s, *data;
unsigned long data_len, descr_len = 0, lang_len = 0;
#ifdef LIBSSH2_DEBUG_TRANSPORT
_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnecting: reason=%d, desc=%s, lang=%s", reason, description, lang);
#endif
if (description) {
descr_len = strlen(description);
}
if (lang) {
lang_len = strlen(lang);
}
data_len = descr_len + lang_len + 13; /* packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
s = data = (unsigned char *) LIBSSH2_ALLOC(session, data_len);
if (!data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for disconnect packet", 0);
return -1;
}
*(s++) = SSH_MSG_DISCONNECT;
libssh2_htonu32(s, reason); s += 4;
libssh2_htonu32(s, descr_len); s += 4;
if (description) {
memcpy(s, description, descr_len);
s += descr_len;
}
libssh2_htonu32(s, lang_len); s += 4;
if (lang) {
memcpy(s, lang, lang_len);
s += lang_len;
}
libssh2_packet_write(session, data, data_len);
LIBSSH2_FREE(session, data);
return 0;
}
/* }}} */
/* {{{ libssh2_session_methods
* Return the currently active methods for method_type
* NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string regardless of actual negotiation
* Strings should NOT be freed
*/
LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type)
{
/* All methods have char *name as their first element */
LIBSSH2_KEX_METHOD *method = NULL;
switch(method_type) {
case LIBSSH2_METHOD_KEX:
method = session->kex;
break;
case LIBSSH2_METHOD_HOSTKEY:
method = (LIBSSH2_KEX_METHOD*)session->hostkey;
break;
case LIBSSH2_METHOD_CRYPT_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.crypt;
break;
case LIBSSH2_METHOD_CRYPT_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.crypt;
break;
case LIBSSH2_METHOD_MAC_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.mac;
break;
case LIBSSH2_METHOD_MAC_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.mac;
break;
case LIBSSH2_METHOD_COMP_CS:
method = (LIBSSH2_KEX_METHOD*)session->local.comp;
break;
case LIBSSH2_METHOD_COMP_SC:
method = (LIBSSH2_KEX_METHOD*)session->remote.comp;
break;
case LIBSSH2_METHOD_LANG_CS:
return "";
break;
case LIBSSH2_METHOD_LANG_SC:
return "";
break;
default:
libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid parameter specified for method_type", 0);
return NULL;
break;
}
if (!method) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No method negotiated", 0);
return NULL;
}
return method->name;
}
/* }}} */
/* {{{ libssh2_session_abstract
* Retrieve a pointer to the abstract property
*/
LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session)
{
return &session->abstract;
}
/* }}} */
/* {{{ libssh2_session_last_error
* Returns error code and populates an error string into errmsg
* If want_buf is non-zero then the string placed into errmsg must be freed by the calling program
* Otherwise it is assumed to be owned by libssh2
*/
LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf)
{
/* No error to report */
if (!session->err_code) {
if (errmsg) {
if (want_buf) {
*errmsg = (char *) LIBSSH2_ALLOC(session, 1);
if (*errmsg) {
**errmsg = 0;
}
} else {
*errmsg = "";
}
}
if (errmsg_len) {
*errmsg_len = 0;
}
return 0;
}
if (errmsg) {
char *serrmsg = session->err_msg ? session->err_msg : (char *) "";
int ownbuf = session->err_msg ? session->err_should_free : 0;
if (want_buf) {
if (ownbuf) {
/* Just give the calling program the buffer */
*errmsg = serrmsg;
session->err_should_free = 0;
} else {
/* Make a copy so the calling program can own it */
*errmsg = (char *) LIBSSH2_ALLOC(session, session->err_msglen + 1);
if (*errmsg) {
memcpy(*errmsg, session->err_msg, session->err_msglen);
(*errmsg)[session->err_msglen] = 0;
}
}
} else {
*errmsg = serrmsg;
}
}
if (errmsg_len) {
*errmsg_len = session->err_msglen;
}
return session->err_code;
}
/* }}} */
/* {{{ libssh2_session_flag
* Set/Get session flags
* Passing flag==0 will avoid changing session->flags while still returning its current value
*/
LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value)
{
if (value) {
session->flags |= flag;
} else {
session->flags &= ~flag;
}
return session->flags;
}
/* }}} */
/* {{{ libssh2_poll_channel_read
* Returns 0 if no data is waiting on channel,
* non-0 if data is available
*/
LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended)
{
LIBSSH2_SESSION *session = channel->session;
LIBSSH2_PACKET *packet = session->packets.head;
while (packet) {
if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) && (extended != 0) && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
/* Found data waiting to be read */
return 1;
}
packet = packet->next;
}
return 0;
}
/* }}} */
/* {{{ libssh2_poll_channel_write
* Returns 0 if writing to channel would block,
* non-0 if data can be written without blocking
*/
inline int libssh2_poll_channel_write(LIBSSH2_CHANNEL *channel)
{
return channel->local.window_size ? 1 : 0;
}
/* }}} */
/* {{{ libssh2_poll_listener_queued
* Returns 0 if no connections are waiting to be accepted
* non-0 if one or more connections are available
*/
inline int libssh2_poll_listener_queued(LIBSSH2_LISTENER *listener)
{
return listener->queue ? 1 : 0;
}
/* }}} */
/* {{{ libssh2_poll
* Poll sockets, channels, and listeners for activity
*/
LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, long timeout)
{
long timeout_remaining;
int i, active_fds;
#ifdef HAVE_POLL
LIBSSH2_SESSION *session = NULL;
struct pollfd sockets[nfds];
/* Setup sockets for polling */
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
sockets[i].fd = fds[i].fd.socket;
sockets[i].events = fds[i].events;
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_CHANNEL:
sockets[i].fd = fds[i].fd.channel->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session) session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
sockets[i].fd = fds[i].fd.listener->session->socket_fd;
sockets[i].events = POLLIN;
sockets[i].revents = 0;
if (!session) session = fds[i].fd.listener->session;
break;
default:
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
return -1;
}
}
#elif defined(HAVE_SELECT)
LIBSSH2_SESSION *session = NULL;
int maxfd = 0;
fd_set rfds,wfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
for(i = 0; i < nfds; i++) {
fds[i].revents = 0;
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (fds[i].events & LIBSSH2_POLLFD_POLLIN) {
FD_SET(fds[i].fd.socket, &rfds);
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
}
if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) {
FD_SET(fds[i].fd.socket, &wfds);
if (fds[i].fd.socket > maxfd) maxfd = fds[i].fd.socket;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
FD_SET(fds[i].fd.channel->session->socket_fd, &rfds);
if (fds[i].fd.channel->session->socket_fd > maxfd) maxfd = fds[i].fd.channel->session->socket_fd;
if (!session) session = fds[i].fd.channel->session;
break;
case LIBSSH2_POLLFD_LISTENER:
FD_SET(fds[i].fd.listener->session->socket_fd, &rfds);
if (fds[i].fd.listener->session->socket_fd > maxfd) maxfd = fds[i].fd.listener->session->socket_fd;
if (!session) session = fds[i].fd.listener->session;
break;
default:
if (session) libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, "Invalid descriptor passed to libssh2_poll()", 0);
return -1;
}
}
#else
/* No select() or poll()
* no sockets sturcture to setup
*/
timeout = 0;
#endif /* HAVE_POLL or HAVE_SELECT */
timeout_remaining = timeout;
do {
#if defined(HAVE_POLL) || defined(HAVE_SELECT)
int sysret;
#endif
active_fds = 0;
for (i = 0; i < (int) nfds; i++) {
if (fds[i].events != fds[i].revents) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_CHANNEL:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want to be ready for read */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* Not yet known to be ready for read */
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 0) ? LIBSSH2_POLLFD_POLLIN : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && /* Want to be ready for extended read */
((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { /* Not yet known to be ready for extended read */
fds[i].revents |= libssh2_poll_channel_read(fds[i].fd.channel, 1) ? LIBSSH2_POLLFD_POLLEXT : 0;
}
if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && /* Want to be ready for write */
((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { /* Not yet known to be ready for write */
fds[i].revents |= libssh2_poll_channel_write(fds[i].fd.channel) ? LIBSSH2_POLLFD_POLLOUT : 0;
}
if (fds[i].fd.channel->remote.close || fds[i].fd.channel->local.close) {
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED;
}
if (fds[i].fd.channel->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
}
break;
case LIBSSH2_POLLFD_LISTENER:
if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && /* Want a connection */
((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { /* No connections known of yet */
fds[i].revents |= libssh2_poll_listener_queued(fds[i].fd.listener) ? LIBSSH2_POLLFD_POLLIN : 0;
}
if (fds[i].fd.listener->session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
}
break;
}
}
if (fds[i].revents) {
active_fds++;
}
}
if (active_fds) {
/* Don't block on the sockets if we have channels/listeners which are ready */
timeout_remaining = 0;
}
#ifdef HAVE_POLL
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *)&tv_begin, NULL);
sysret = poll(sockets, nfds, timeout_remaining);
gettimeofday((struct timeval *)&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = poll(sockets, nfds, timeout_remaining);
timeout_remaining = 0;
#endif /* HAVE_GETTIMEOFDAY */
if (sysret > 0) {
for (i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
fds[i].revents = sockets[i].revents;
sockets[i].revents = 0; /* In case we loop again, be nice */
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
}
if (sockets[i].revents & POLLHUP) {
fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
}
sockets[i].revents = 0;
break;
case LIBSSH2_POLLFD_LISTENER:
if (sockets[i].events & POLLIN) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
}
if (sockets[i].revents & POLLHUP) {
fds[i].revents |= LIBSSH2_POLLFD_LISTENER_CLOSED | LIBSSH2_POLLFD_SESSION_CLOSED;
}
sockets[i].revents = 0;
break;
}
}
}
#elif defined(HAVE_SELECT)
tv.tv_sec = timeout_remaining / 1000;
tv.tv_usec = (timeout_remaining % 1000) * 1000;
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv_begin, tv_end;
gettimeofday((struct timeval *)&tv_begin, NULL);
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
gettimeofday((struct timeval *)&tv_end, NULL);
timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000;
timeout_remaining -= ceil((tv_end.tv_usec - tv_begin.tv_usec) / 1000);
}
#else
/* If the platform doesn't support gettimeofday,
* then just make the call non-blocking and walk away
*/
sysret = select(maxfd, &rfds, &wfds, NULL, &tv);
timeout_remaining = 0;
#endif
if (sysret > 0) {
for (i = 0; i < nfds; i++) {
switch (fds[i].type) {
case LIBSSH2_POLLFD_SOCKET:
if (FD_ISSET(fds[i].fd.socket, &rfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLIN;
}
if (FD_ISSET(fds[i].fd.socket, &wfds)) {
fds[i].revents |= LIBSSH2_POLLFD_POLLOUT;
}
if (fds[i].revents) {
active_fds++;
}
break;
case LIBSSH2_POLLFD_CHANNEL:
if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.channel->session, 0) > 0);
}
break;
case LIBSSH2_POLLFD_LISTENER:
if (FD_ISSET(fds[i].fd.listener->session->socket_fd, &rfds)) {
/* Spin session until no data available */
while (libssh2_packet_read(fds[i].fd.listener->session, 0) > 0);
}
break;
}
}
}
#endif /* else no select() or poll() -- timeout (and by extension timeout_remaining) will be equal to 0 */
} while ((timeout_remaining > 0) && !active_fds);
return active_fds;
}
/* }}} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,855 @@
/* Copyright (c) 2004-2005, Sara Golemon <sarag@libssh2.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* Neither the name of the copyright holder nor the names
* of any other contributors may be used to endorse or
* promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
#include "libssh2_priv.h"
/* Needed for struct iovec on some platforms */
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
/* {{{ proto libssh2_userauth_list
* List authentication methods
* Will yield successful login if "none" happens to be allowable for this user
* Not a common configuration for any SSH server though
* username should be NULL, or a null terminated string
*/
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, int username_len)
{
unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
method_len(4) + method(4)"none" */
unsigned long methods_len;
unsigned char *data, *s;
s = data = (unsigned char *) LIBSSH2_ALLOC(session, data_len);
if (!data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth_list", 0);
return NULL;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
if (username) {
memcpy(s, username, username_len); s += username_len;
}
libssh2_htonu32(s, 14); s += 4;
memcpy(s, "ssh-connection", 14); s += 14;
libssh2_htonu32(s, 4); s += 4;
memcpy(s, "none", 4); s += 4;
if (libssh2_packet_write(session, data, data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-none request", 0);
LIBSSH2_FREE(session, data);
return NULL;
}
LIBSSH2_FREE(session, data);
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return NULL;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
/* Wow, who'dve thought... */
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return NULL;
}
methods_len = libssh2_ntohu32(data + 1);
memcpy(data, data + 5, methods_len);
data[methods_len] = '\0';
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
#endif
return (char *) data;
}
/* }}} */
/* {{{ libssh2_userauth_authenticated
* 0 if not yet authenticated
* non-zero is already authenticated
*/
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session)
{
return session->state & LIBSSH2_STATE_AUTHENTICATED;
}
/* }}} */
/* {{{ libssh2_userauth_password
* Plain ol' login
*/
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
const char *password, int password_len,
LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{
unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
unsigned long data_len = username_len + password_len + 40; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
method_len(4) + method(8)"password" + chgpwdbool(1) + password_len(4) */
s = data = (unsigned char *) LIBSSH2_ALLOC(session, data_len);
if (!data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password request", 0);
return -1;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
*s = '\0'; s++;
libssh2_htonu32(s, password_len); s += 4;
memcpy(s, password, password_len); s += password_len;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
#endif
if (libssh2_packet_write(session, data, data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
LIBSSH2_FREE(session, data);
return -1;
}
LIBSSH2_FREE(session, data);
password_response:
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password authentication successful");
#endif
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
char *newpw = NULL;
int newpw_len = 0;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
#endif
LIBSSH2_FREE(session, data);
if (passwd_change_cb) {
passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
if (!newpw) {
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
return -1;
}
data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
s = data = (unsigned char *) LIBSSH2_ALLOC(session, data_len);
if (!data) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
return -1;
}
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
libssh2_htonu32(s, sizeof("password") - 1); s += 4;
memcpy(s, "password", sizeof("password") - 1); s += sizeof("password") - 1;
*s = 0xFF; s++;
libssh2_htonu32(s, password_len); s += 4;
memcpy(s, password, password_len); s += password_len;
libssh2_htonu32(s, newpw_len); s += 4;
memcpy(s, newpw, newpw_len); s += newpw_len;
if (libssh2_packet_write(session, data, data_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
LIBSSH2_FREE(session, data);
return -1;
}
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, newpw);
/* Ugliest use of goto ever. Blame it on the askN => requirev migration. */
goto password_response;
} else {
libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
return -1;
}
}
/* FAILURE */
LIBSSH2_FREE(session, data);
return -1;
}
/* }}} */
/* {{{ libssh2_file_read_publickey
* Read a public key from an id_???.pub style file
*/
static int libssh2_file_read_publickey(LIBSSH2_SESSION *session, unsigned char **method, unsigned long *method_len,
unsigned char **pubkeydata, unsigned long *pubkeydata_len,
const char *pubkeyfile)
{
FILE *fd;
char *pubkey = NULL, c, *sp1, *sp2, *tmp;
int pubkey_len = 0, tmp_len;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s", pubkeyfile);
#endif
/* Read Public Key */
fd = fopen(pubkeyfile, "r");
if (!fd) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to open public key file", 0);
return -1;
}
while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n') pubkey_len++;
rewind(fd);
if (pubkey_len <= 1) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid data in public key file", 0);
fclose(fd);
return -1;
}
pubkey = (char *) LIBSSH2_ALLOC(session, pubkey_len);
if (!pubkey) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for public key data", 0);
fclose(fd);
return -1;
}
if (fread(pubkey, 1, pubkey_len, fd) != (unsigned int) pubkey_len) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to read public key from file", 0);
LIBSSH2_FREE(session, pubkey);
fclose(fd);
return -1;
}
fclose(fd);
while (pubkey_len && (pubkey[pubkey_len-1] == '\r' || pubkey[pubkey_len-1] == '\n')) pubkey_len--;
if (!pubkey_len) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data", 0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
if ((sp1 = (char *) memchr(pubkey, ' ', pubkey_len)) == NULL) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data", 0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
/* Wasting some bytes here (okay, more than some),
* but since it's likely to be freed soon anyway,
* we'll just avoid the extra free/alloc and call it a wash */
*method = (unsigned char *) pubkey;
*method_len = sp1 - pubkey;
sp1++;
if ((sp2 = (char *) memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
/* Assume that the id string is missing, but that it's okay */
sp2 = pubkey + pubkey_len;
}
if (libssh2_base64_decode(session, &tmp, &tmp_len, sp1, sp2 - sp1)) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid key data, not base64 encoded", 0);
LIBSSH2_FREE(session, pubkey);
return -1;
}
*pubkeydata = (unsigned char *) tmp;
*pubkeydata_len = tmp_len;
return 0;
}
/* }}} */
/* {{{ libssh2_file_read_privatekey
* Read a PEM encoded private key from an id_??? style file
*/
static int libssh2_file_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
const char *method, int method_len,
const char *privkeyfile, const char *passphrase)
{
LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = libssh2_hostkey_methods();
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s", privkeyfile);
#endif
*hostkey_method = NULL;
*hostkey_abstract = NULL;
while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
if ((*hostkey_methods_avail)->initPEM &&
strncmp((*hostkey_methods_avail)->name, method, method_len) == 0) {
*hostkey_method = *hostkey_methods_avail;
break;
}
hostkey_methods_avail++;
}
if (!*hostkey_method) {
libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No handler for specified private key", 0);
return -1;
}
if ((*hostkey_method)->initPEM(session, (unsigned char *) privkeyfile, (unsigned char *) passphrase, hostkey_abstract)) {
libssh2_error(session, LIBSSH2_ERROR_FILE, "Unable to initialize private key from file", 0);
return -1;
}
return 0;
}
/* }}} */
/* {{{ libssh2_userauth_hostbased_fromfile_ex
* Authenticate using a keypair found in the named files
*/
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
const char *publickey, const char *privatekey,
const char *passphrase,
const char *hostname, int hostname_len,
const char *local_username, int local_username_len)
{
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract;
unsigned char buf[5];
struct iovec datavec[4];
unsigned char *method, *pubkeydata, *packet, *s, *sig, *data, reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
return -1;
}
packet_len = username_len + method_len + hostname_len + local_username_len + pubkeydata_len + 48;
/* packet_type(1) + username_len(4) + servicename_len(4) + service_name(14)"ssh-connection" +
* authmethod_len(4) + authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
* local_username_len(4)
*/
/* Preallocate space for an overall length, method name again,
* and the signature, which won't be any larger than the size of the publickeydata itself */
s = packet = (unsigned char *) LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
libssh2_htonu32(s, 14); s += 4;
memcpy(s, "ssh-connection", 14); s += 14;
libssh2_htonu32(s, 9); s += 4;
memcpy(s, "hostbased", 9); s += 9;
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
libssh2_htonu32(s, pubkeydata_len); s += 4;
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
libssh2_htonu32(s, hostname_len); s += 4;
memcpy(s, hostname, hostname_len); s += hostname_len;
libssh2_htonu32(s, local_username_len); s += 4;
memcpy(s, local_username, local_username_len); s += local_username_len;
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, (char *) method, method_len, privatekey, passphrase)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
return -1;
}
libssh2_htonu32(buf, session->session_id_len);
datavec[0].iov_base = (char *) buf;
datavec[0].iov_len = 4;
datavec[1].iov_base = (char *) session->session_id;
datavec[1].iov_len = session->session_id_len;
datavec[2].iov_base = (char *) packet;
datavec[2].iov_len = packet_len;
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
return -1;
}
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
if (sig_len > pubkeydata_len ) {
/* Should *NEVER* happen, but...well.. better safe than sorry */
packet = (unsigned char *) LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-hostbased packet", 0);
LIBSSH2_FREE(session, method);
return -1;
}
}
s = packet + packet_len;
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
LIBSSH2_FREE(session, method);
libssh2_htonu32(s, sig_len); s += 4;
memcpy(s, sig, sig_len); s += sig_len;
LIBSSH2_FREE(session, sig);
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting hostbased authentication");
#endif
if (libssh2_packet_write(session, packet, s - packet)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-hostbased request", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Hostbased authentication successful");
#endif
/* We are us and we've proved it. */
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
return -1;
}
/* }}} */
/* {{{ libssh2_userauth_publickey_fromfile_ex
* Authenticate using a keypair found in the named files
*/
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
const char *publickey, const char *privatekey,
const char *passphrase)
{
LIBSSH2_HOSTKEY_METHOD *privkeyobj;
void *abstract;
unsigned char buf[5];
struct iovec datavec[4];
unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
return -1;
}
packet_len = username_len + method_len + pubkeydata_len + 45; /* packet_type(1) + username_len(4) + servicename_len(4) +
service_name(14)"ssh-connection" + authmethod_len(4) +
authmethod(9)"publickey" + sig_included(1)'\0' +
algmethod_len(4) + publickey_len(4) */
/* Preallocate space for an overall length, method name again,
* and the signature, which won't be any larger than the size of the publickeydata itself */
s = packet = (unsigned char *) LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
*(s++) = SSH_MSG_USERAUTH_REQUEST;
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
libssh2_htonu32(s, 14); s += 4;
memcpy(s, "ssh-connection", 14); s += 14;
libssh2_htonu32(s, 9); s += 4;
memcpy(s, "publickey", 9); s += 9;
b = s;
*(s++) = 0; /* Not sending signature with *this* packet */
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
libssh2_htonu32(s, pubkeydata_len); s += 4;
memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
#endif
if (libssh2_packet_write(session, packet, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata);
return -1;
}
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata);
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
#endif
/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, packet);
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, pubkeydata);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
return -1;
}
/* Semi-Success! */
LIBSSH2_FREE(session, data);
LIBSSH2_FREE(session, pubkeydata);
if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, (char *) method, method_len, privatekey, passphrase)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
return -1;
}
*b = 0xFF;
libssh2_htonu32(buf, session->session_id_len);
datavec[0].iov_base = (char *) buf;
datavec[0].iov_len = 4;
datavec[1].iov_base = (char *) session->session_id;
datavec[1].iov_len = session->session_id_len;
datavec[2].iov_base = (char *) packet;
datavec[2].iov_len = packet_len;
if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
LIBSSH2_FREE(session, method);
LIBSSH2_FREE(session, packet);
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
return -1;
}
if (privkeyobj->dtor) {
privkeyobj->dtor(session, &abstract);
}
if (sig_len > pubkeydata_len) {
/* Should *NEVER* happen, but...well.. better safe than sorry */
packet = (unsigned char *) LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
if (!packet) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-publickey packet", 0);
LIBSSH2_FREE(session, method);
return -1;
}
}
s = packet + packet_len;
libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
libssh2_htonu32(s, method_len); s += 4;
memcpy(s, method, method_len); s += method_len;
LIBSSH2_FREE(session, method);
libssh2_htonu32(s, sig_len); s += 4;
memcpy(s, sig, sig_len); s += sig_len;
LIBSSH2_FREE(session, sig);
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
#endif
if (libssh2_packet_write(session, packet, s - packet)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
LIBSSH2_FREE(session, packet);
return -1;
}
LIBSSH2_FREE(session, packet);
/* PK_OK is no longer valid */
reply_codes[2] = 0;
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
#endif
/* We are us and we've proved it. */
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
/* This public key is not allowed for this user on this server */
LIBSSH2_FREE(session, data);
libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
return -1;
}
/* }}} */
/* {{{ libssh2_userauth_keyboard_interactive
* Authenticate using a challenge-response authentication
*/
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
unsigned char *s, *data; /* packet */
unsigned long packet_len;
packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
+ 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
+ 4 + 14 /* string service name (US-ASCII) */
+ 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
+ 4 + 0 /* string language tag (as defined in [RFC-3066]) */
+ 4 + 0 /* string submethods (ISO-10646 UTF-8) */
;
if (!(data = s = (unsigned char *) LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
return -1;
}
*s++ = SSH_MSG_USERAUTH_REQUEST;
/* user name */
libssh2_htonu32(s, username_len); s += 4;
memcpy(s, username, username_len); s += username_len;
/* service name */
libssh2_htonu32(s, sizeof("ssh-connection") - 1); s += 4;
memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1); s += sizeof("ssh-connection") - 1;
/* "keyboard-interactive" */
libssh2_htonu32(s, sizeof("keyboard-interactive") - 1); s += 4;
memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1); s += sizeof("keyboard-interactive") - 1;
/* language tag */
libssh2_htonu32(s, 0); s += 4;
/* submethods */
libssh2_htonu32(s, 0); s += 4;
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
#endif
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
LIBSSH2_FREE(session, data);
return -1;
}
LIBSSH2_FREE(session, data);
for (;;) {
unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
unsigned int auth_name_len;
char* auth_name = NULL;
unsigned auth_instruction_len;
char* auth_instruction = NULL;
unsigned int language_tag_len;
unsigned long data_len;
unsigned int num_prompts = 0;
unsigned int i;
int auth_failure = 1;
LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;
if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
return -1;
}
if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
#endif
LIBSSH2_FREE(session, data);
session->state |= LIBSSH2_STATE_AUTHENTICATED;
return 0;
}
if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
LIBSSH2_FREE(session, data);
return -1;
}
/* server requested PAM-like conversation */
s = data + 1;
/* string name (ISO-10646 UTF-8) */
auth_name_len = libssh2_ntohu32(s); s += 4;
if (!(auth_name = (char *) LIBSSH2_ALLOC(session, auth_name_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
goto cleanup;
}
memcpy(auth_name, s, auth_name_len); s += auth_name_len;
/* string instruction (ISO-10646 UTF-8) */
auth_instruction_len = libssh2_ntohu32(s); s += 4;
if (!(auth_instruction = (char *) LIBSSH2_ALLOC(session, auth_instruction_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
goto cleanup;
}
memcpy(auth_instruction, s, auth_instruction_len); s += auth_instruction_len;
/* string language tag (as defined in [RFC-3066]) */
language_tag_len = libssh2_ntohu32(s); s += 4;
/* ignoring this field as deprecated */ s += language_tag_len;
/* int num-prompts */
num_prompts = libssh2_ntohu32(s); s += 4;
prompts = (LIBSSH2_USERAUTH_KBDINT_PROMPT *) LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
if (!prompts) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
goto cleanup;
}
memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
responses = (LIBSSH2_USERAUTH_KBDINT_RESPONSE *) LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
if (!responses) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
goto cleanup;
}
memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
for(i = 0; i != num_prompts; ++i) {
/* string prompt[1] (ISO-10646 UTF-8) */
prompts[i].length = libssh2_ntohu32(s); s += 4;
if (!(prompts[i].text = (char *) LIBSSH2_ALLOC(session, prompts[i].length))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
goto cleanup;
}
memcpy(prompts[i].text, s, prompts[i].length); s += prompts[i].length;
/* boolean echo[1] */
prompts[i].echo = *s++;
}
response_callback(auth_name, auth_name_len, auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);
#ifdef LIBSSH2_DEBUG_USERAUTH
_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
#endif
packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
+ 4 /* int num-responses */
;
for (i = 0; i != num_prompts; ++i) {
packet_len += 4 + responses[i].length; /* string response[1] (ISO-10646 UTF-8) */
}
if (!(data = s = (unsigned char *) LIBSSH2_ALLOC(session, packet_len))) {
libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
goto cleanup;
}
*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
libssh2_htonu32(s, num_prompts); s += 4;
for (i = 0; i != num_prompts; ++i) {
libssh2_htonu32(s, responses[i].length); s += 4;
memcpy(s, responses[i].text, responses[i].length); s += responses[i].length;
}
if (libssh2_packet_write(session, data, packet_len)) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
goto cleanup;
}
auth_failure = 0;
cleanup:
/* It's safe to clean all the data here, because unallocated pointers
* are filled by zeroes
*/
LIBSSH2_FREE(session, data);
if (prompts) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, prompts[i].text);
}
}
if (responses) {
for (i = 0; i != num_prompts; ++i) {
LIBSSH2_FREE(session, responses[i].text);
}
}
LIBSSH2_FREE(session, prompts);
LIBSSH2_FREE(session, responses);
if (auth_failure) {
return -1;
}
}
}
/* }}} */

View File

@ -0,0 +1,249 @@
/* Class to abstract an SSH client. It uses libssh2.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_ssh_client.h"
#include "../misc/pandora_file.h"
#include "../pandora_strutils.h"
#include "libssh2/libssh2_sftp.h"
#include <winsock2.h>
#include <fstream>
#include <fcntl.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <iostream>
using namespace std;
using namespace SSH;
using namespace Pandora;
Connection_Failed::Connection_Failed (int e) {
err_number = e;
}
int
Connection_Failed::getError () {
return err_number;
}
Scp_Failed::Scp_Failed (char *e) {
errmsg = strdup (e);
}
Pandora_Ssh_Client::Pandora_Ssh_Client () {
sock = 0;
fingerprint = "";
session = NULL;
channel = NULL;
return;
}
Pandora_Ssh_Client::~Pandora_Ssh_Client () {
if (session != NULL) {
disconnect ();
}
return;
}
/* Disconnects from remote host. It will close all open connections and channels. */
void
Pandora_Ssh_Client::disconnect () {
if (channel != NULL) {
libssh2_channel_send_eof (channel);
libssh2_channel_close (channel);
libssh2_channel_wait_closed (channel);
libssh2_channel_free (channel);
channel = NULL;
}
if (session != NULL) {
libssh2_session_disconnect (session, "");
libssh2_session_free (session);
session = NULL;
}
if (sock != 0) {
closesocket (sock);
sock = 0;
}
}
void
Pandora_Ssh_Client::newConnection (const string host, const int port) {
struct sockaddr_in sin;
struct hostent *resolv = NULL;
WSADATA wsadata;
string finger_aux;
char char_aux[3];
if (session != NULL) {
throw Session_Already_Opened ();
}
WSAStartup (2, &wsadata);
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
throw Socket_Error ();
}
resolv = (struct hostent *) gethostbyname (host.c_str ());
if (resolv == NULL) {
disconnect ();
throw Resolv_Failed ();
}
sin.sin_family = AF_INET;
sin.sin_port = htons (port);
sin.sin_addr = *((struct in_addr *)resolv->h_addr);
if (connect (sock, (struct sockaddr*) (&sin),
sizeof (struct sockaddr_in)) == -1) {
disconnect ();
throw Connection_Failed (WSAGetLastError ());
}
session = libssh2_session_init();
if (libssh2_session_startup (session, sock) != 0) {
disconnect ();
throw Session_Error ();
}
/* Get the fingerprint and transform it to a hexadecimal readable
string */
finger_aux = libssh2_hostkey_hash (session,
LIBSSH2_HOSTKEY_HASH_MD5);
fingerprint = "";
for (int i = 0; i < 16; i++) {
sprintf (char_aux, "%02X:", (unsigned char) finger_aux[i]);
fingerprint += (char *) char_aux;
}
fingerprint.erase (fingerprint.length () - 1, 2);
}
/* Connects to specified host and port using a username and a password */
void
Pandora_Ssh_Client::connectWithUserPass (const string host, const int port,
const string username, const string passwd) {
try {
newConnection (host, port);
} catch (Session_Already_Opened e) {
}
if (session != NULL) {
if (libssh2_userauth_password (session, username.c_str (),
passwd.c_str ())) {
disconnect ();
throw Authentication_Failed ();
}
}
return;
}
/* Connects to specified host and port using a username and a public/private key.
* The keys are the filename that contains the public and the private keys.
* The passphrase is the password for these keys. */
void
Pandora_Ssh_Client::connectWithPublicKey (const string host, const int port,
const string username, const string filename_pubkey,
const string filename_privkey, const string passphrase) {
try {
newConnection (host, port);
} catch (Session_Already_Opened e) {
}
if (session != NULL) {
if (libssh2_userauth_publickey_fromfile (session,
username.c_str (),
filename_pubkey.c_str (),
filename_privkey.c_str (),
passphrase.c_str ())) {
disconnect ();
throw Authentication_Failed ();
}
}
return;
}
/* Copy a file using a SSH connection (scp).
* The function receives a filename in the local filesystem and copies all
* its content to the remote host. The remote filename will be the
* basename of the local file and will be copied in the remote actual
* directory. */
void
Pandora_Ssh_Client::scpFileFilename (const string remote_filename, const string filename) {
LIBSSH2_CHANNEL *scp_channel;
size_t to_send, sent;
char *errmsg;
int errmsg_len;
string buffer;
if (session == NULL) {
throw Session_Not_Opened ();
}
try {
buffer = Pandora_File::readFile (filename);
} catch (Pandora_File::File_Not_Found e) {
pandoraLog ("Pandora_Ssh_Client: File %s not found",
filename.c_str());
return;
}
to_send = buffer.length ();
scp_channel = libssh2_scp_send (session, remote_filename.c_str (), 0666,
to_send);
if (scp_channel == NULL) {
throw Channel_Error ();
}
libssh2_channel_set_blocking (scp_channel, 1);
/* FIXME: It may crash if the scp fails, maybe because of a libssh2 bug */
sent = libssh2_channel_write (scp_channel, buffer.c_str (), to_send);
if (sent < 0) {
Scp_Failed *e;
errmsg = (char *) malloc (sizeof (char) * 1000);
libssh2_session_last_error (session, &errmsg, &errmsg_len, 1);
pandoraDebug ("Error %d on SCP %s", sent, errmsg);
e = new Scp_Failed (errmsg);
libssh2_channel_close (scp_channel);
libssh2_channel_wait_closed (scp_channel);
libssh2_channel_free (scp_channel);
Pandora::pandoraFree (errmsg);
throw *e;
}
libssh2_channel_send_eof (scp_channel);
libssh2_channel_close (scp_channel);
libssh2_channel_wait_closed (scp_channel);
libssh2_channel_free (scp_channel);
}
string
Pandora_Ssh_Client::getFingerprint () {
return this->fingerprint;
}

View File

@ -0,0 +1,112 @@
/* Class to abstract an SSH client. It uses libssh2.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_SSH_CLIENT_H__
#define __PANDORA_SSH_CLIENT_H__
#include <string>
#include "../pandora.h"
#include "libssh2/libssh2.h"
using namespace std;
namespace SSH {
/* SSH Client exceptions */
class Session_Already_Opened : public Pandora::Pandora_Exception {
};
class Session_Not_Opened : public Pandora::Pandora_Exception {
};
class Session_Error : public Pandora::Pandora_Exception {
};
class Authentication_Failed : public Pandora::Pandora_Exception {
};
class Resolv_Failed : public Pandora::Pandora_Exception {
};
class Socket_Error : public Pandora::Pandora_Exception {
};
class File_Error : public Pandora::Pandora_Exception {
};
class Channel_Error : public Pandora::Pandora_Exception {
};
class Connection_Failed : public Pandora::Pandora_Exception {
private:
int err_number;
public:
Connection_Failed (int e);
int getError ();
};
class Scp_Failed : public Pandora::Pandora_Exception {
private:
char *errmsg;
public:
Scp_Failed (char *e);
~Scp_Failed () { Pandora::pandoraFree (errmsg); };
};
/* SSH Client class */
class Pandora_Ssh_Client {
private:
int sock;
string fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
void newConnection (const string host, const int port);
public:
Pandora_Ssh_Client ();
~Pandora_Ssh_Client ();
/* Connects to specified host and port using a username and a password
*
* Throws: Authentication_Failed */
void connectWithUserPass (const string host, const int port,
const string username, const string passwd);
/* Connects to specified host and port using a username and a public/private key.
* The keys are the filename that contains the public and the private keys.
* The passphrase is the password for these keys.
*
* Throws: Authentication_Failed */
void connectWithPublicKey (const string host, const int port,
const string username, const string filename_pubkey,
const string filename_privkey, const string passphrase);
/* Disconnects from remote host. It will close all open connections and channels. */
void disconnect ();
/* Copy a file using a SSH connection (scp).
* The function receives a filename in the local filesystem and copies all
* its content to the remote host. The remote filename will be the
* first argument. */
void scpFileFilename (const string remote_filename,
const string filename);
string getFingerprint ();
};
}
#endif

View File

@ -0,0 +1,157 @@
/* Test module to prove SSH connection.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_ssh_test.h"
#include "../pandora_agent_conf.h"
#include "../tinyxml/tinyxml.h"
#include "../misc/pandora_file.h"
#include <iostream>
using namespace std;
using namespace SSH;
Pandora_SSH_Test::Pandora_SSH_Test () {
string conf_file;
conf_file = Pandora::getPandoraInstallDir ();
conf_file += "pandora_agent.conf";
conf = new Pandora_Agent_Conf (conf_file);
ssh_client = new SSH::Pandora_Ssh_Client ();
}
Pandora_SSH_Test::~Pandora_SSH_Test () {
delete conf;
delete ssh_client;
}
void
Pandora_SSH_Test::test () {
string pubkey_file, privkey_file, tmp_filename;
string remote_host, remote_filepath, tmp_filepath;
TiXmlDocument *doc;
TiXmlDeclaration *decl;
bool saved;
remote_host = this->conf->getValue ("server_ip");
pubkey_file = Pandora::getPandoraInstallDir ();
pubkey_file += "key\\id_dsa.pub";
privkey_file = Pandora::getPandoraInstallDir ();
privkey_file += "key\\id_dsa";
cout << "Public key file: " << pubkey_file << endl;
cout << "Private key file: " << privkey_file << endl;
cout << "Connecting with " << remote_host << "..." << endl;
try {
this->ssh_client->connectWithPublicKey (remote_host.c_str (), 22,
"pandora", pubkey_file,
privkey_file, "");
} catch (Authentication_Failed e) {
cout << "Authentication Failed when connecting to "
<< remote_host << endl;
cout << "Check the remote host configuration and the public/private key files."
<< endl;
throw e;
} catch (Socket_Error e) {
cout << "Socket error when connecting to "
<< remote_host << endl;
cout << "Check the network configuration." << endl;
throw e;
} catch (Resolv_Failed e) {
cout << "Could not resolv "
<< remote_host << endl;
cout << "Check the network configuration." << endl;
throw e;
} catch (Connection_Failed e) {
cout << "Connection error number " << e.getError () << endl;
cout << "Check the network configuration." << endl;
throw e;
} catch (Session_Error e) {
cout << "Error while opening SSH session." << endl;
cout << "Check the network configuration." << endl;
throw e;
}
cout << "Authentication successful." << endl;
cout << "Host fingerprint: " << this->ssh_client->getFingerprint ()
<< endl;
tmp_filename = "ssh.test";
tmp_filepath = conf->getValue ("temporal");
if (tmp_filepath[tmp_filepath.length () - 1] != '\\') {
tmp_filepath += "\\";
}
tmp_filepath += tmp_filename;
decl = new TiXmlDeclaration( "1.0", "ISO-8859-1", "" );
doc = new TiXmlDocument (tmp_filepath);
doc->InsertEndChild (*decl);
saved = doc->SaveFile();
delete doc;
if (!saved) {
Pandora_Exception e;
cout << "Error when saving the XML in " << tmp_filepath << endl;
cout << "Check the configuration file" << endl;
throw e;
}
cout << "Created a blank XML file in " << tmp_filepath<< endl;
remote_filepath = conf->getValue ("server_path");
cout << "Remote copying " << tmp_filepath << "on server " << remote_host
<< " at " << remote_filepath << tmp_filename << endl;
try {
ssh_client->scpFileFilename (remote_filepath + tmp_filename,
tmp_filepath);
} catch (Session_Not_Opened e) {
ssh_client->disconnect();
cout << "The SSH session could not be created." << endl;
cout << "Check the network configuration." << endl;
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_Exception e) {
}
throw e;
} catch (Scp_Failed e) {
ssh_client->disconnect();
cout << "The copying operation could not finished." << endl;
cout << "Check the network configuration." << endl;
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_Exception e) {
}
throw e;
} catch (Pandora_Exception e) {
ssh_client->disconnect();
cout << "An unhandled exception happened." << endl;
throw e;
}
cout << "Successfuly file copied to remote host " << endl;
ssh_client->disconnect();
cout << "Successfuly disconnected from remote host " << endl;
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
cout << "The SSH test was successful!" << endl;
}

View File

@ -0,0 +1,34 @@
/* Test module to prove SSH connection.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_ssh_client.h"
#include "../pandora_agent_conf.h"
namespace SSH {
class Pandora_SSH_Test {
private:
Pandora_Ssh_Client *ssh_client;
Pandora_Agent_Conf *conf;
public:
Pandora_SSH_Test ();
~Pandora_SSH_Test ();
void test ();
};
}

View File

@ -0,0 +1,58 @@
/* Functions to get information about Windows.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "pandora_windows_info.h"
#include "../pandora_strutils.h"
#define MAX_KEY_LENGTH 255
using namespace Pandora_Strutils;
using namespace Pandora_Windows_Info;
string
Pandora_Windows_Info::getOSName () {
return Pandora_Wmi::getOSName ();
}
string
Pandora_Windows_Info::getOSVersion () {
return Pandora_Wmi::getOSVersion ();
}
string
Pandora_Windows_Info::getOSBuild () {
return Pandora_Wmi::getOSBuild();
}
string
Pandora_Windows_Info::getSystemName () {
return Pandora_Wmi::getSystemName ();
}
string
Pandora_Windows_Info::getSystemPath () {
char buffer[MAX_PATH];
::GetWindowsDirectory (buffer, MAX_PATH+1);
string str_path = buffer;
str_path = trim (str_path);
return str_path;
}

View File

@ -0,0 +1,41 @@
/* Functions to get information about Windows operating system.
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_WINDOWS_INFO_H__
#define __PANDORA_WINDOWS_INFO_H__
#include <windows.h>
#include "../pandora.h"
#include <list>
#include <string>
#include "pandora_wmi.h"
using namespace Pandora;
using namespace std;
namespace Pandora_Windows_Info {
string getOSName ();
string getOSVersion ();
string getOSBuild ();
string getSystemName ();
string getSystemPath ();
}
#endif

View File

@ -0,0 +1,267 @@
/* Class to manage the Windows Management Instrumentation(WMI).
It depends on disphelper library (http://disphelper.sourceforge.net)
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MAB02111-1307, USA.
*/
#include "pandora_wmi.h"
#include "../pandora_strutils.h"
#include <iostream>
#include <algorithm>
#include <cctype>
using namespace std;
using namespace Pandora_Wmi;
static LPWSTR
getWmiStr (LPCWSTR computer) {
static WCHAR wmi_str [256];
wcscpy (wmi_str, L"winmgmts:{impersonationLevel=impersonate}!\\\\");
if (computer) {
wcsncat (wmi_str, computer, 128);
} else {
wcscat (wmi_str, L".");
}
wcscat (wmi_str, L"\\root\\cimv2");
return wmi_str;
}
int
Pandora_Wmi::isProcessRunning (string process_name) {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string name;
int result = 0;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, description, state;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_Process"));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".Name");
name = fix.name;
transform (name.begin (), name.end (), name.begin (),
(int (*) (int)) tolower);
pandoraDebug ("name %s", name.c_str ());
if (process_name == name) {
result++;
}
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return result;
}
int
Pandora_Wmi::isServiceRunning (string service_name) {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string name, state;
int result = 0;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, state;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_Service"));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".Name");
name = fix.name;
transform (name.begin (), name.end (), name.begin (),
(int (*) (int)) tolower);
pandoraDebug ("name %s", name.c_str ());
if (service_name == name) {
dhGetValue (L"%s", &fix.state, quickfix,
L".State");
state = fix.state;
pandoraDebug ("state %s", state.c_str ());
}
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return result;
}
string
Pandora_Wmi::getOSName () {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string ret;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, state, description;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_OperatingSystem "));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".Caption");
ret = fix.name;
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return ret;
}
string
Pandora_Wmi::getOSVersion () {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string ret;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, state, description;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_OperatingSystem "));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".CSDVersion");
ret = fix.name;
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return ret;
}
string
Pandora_Wmi::getOSBuild () {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string ret;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, state, description;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_OperatingSystem "));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".Version");
ret = fix.name;
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return ret;
}
string
Pandora_Wmi::getSystemName () {
CDhInitialize init;
CDispPtr wmi_svc, quickfixes;
string ret;
dhToggleExceptions (TRUE);
struct QFix {
CDhStringA name, state, description;
};
try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%S)",
L"SELECT * FROM Win32_OperatingSystem "));
FOR_EACH (quickfix, quickfixes, NULL) {
QFix fix = { 0 };
dhGetValue (L"%s", &fix.name, quickfix,
L".CSName");
ret = fix.name;
} NEXT_THROW (quickfix);
} catch (string errstr) {
cerr << "Fatal error details:" << endl << errstr << endl;
}
return ret;
}

View File

@ -0,0 +1,41 @@
/* Class to manage the Windows Management Instrumentation(WMI).
It depends on disphelper library (http://disphelper.sourceforge.net)
Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez.
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 2, 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, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __PANDORA_WMI_H__
#define __PANDORA_WMI_H__
#include "../pandora.h"
#include "wmi/disphelper.h"
#include <list>
using namespace Pandora;
using namespace std;
namespace Pandora_Wmi {
int isProcessRunning (string process_name);
int isServiceRunning (string service_name);
string getOSName ();
string getOSVersion ();
string getOSBuild ();
string getSystemName ();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,731 @@
/* This file is part of the source code for the DispHelper COM helper library.
* DispHelper allows you to call COM objects with an extremely simple printf style syntax.
* DispHelper can be used from C++ or even plain C. It works with most Windows compilers
* including Dev-CPP, Visual C++ and LCC-WIN32. Including DispHelper in your project
* couldn't be simpler as it is available in a compacted single file version.
*
* Included with DispHelper are over 20 samples that demonstrate using COM objects
* including ADO, CDO, Outlook, Eudora, Excel, Word, Internet Explorer, MSHTML,
* PocketSoap, Word Perfect, MS Agent, SAPI, MSXML, WIA, dexplorer and WMI.
*
* DispHelper is free open source software provided under the BSD license.
*
* Find out more and download DispHelper at:
* http://sourceforge.net/projects/disphelper/
* http://disphelper.sourceforge.net/
*/
#ifndef DISPHELPER_H_INCLUDED
#define DISPHELPER_H_INCLUDED
#include <objbase.h>
#include <time.h>
#ifdef __cplusplus
extern "C" {
#endif
HRESULT dhCreateObject(LPCOLESTR szProgId, LPCWSTR szMachine, IDispatch ** ppDisp);
HRESULT dhGetObject(LPCOLESTR szFile, LPCOLESTR szProgId, IDispatch ** ppDisp);
HRESULT dhCreateObjectEx(LPCOLESTR szProgId, REFIID riid, DWORD dwClsContext, COSERVERINFO * pServerInfo, void ** ppv);
HRESULT dhGetObjectEx(LPCOLESTR szFile, LPCOLESTR szProgId, REFIID riid, DWORD dwClsContext, LPVOID lpvReserved, void ** ppv);
HRESULT dhCallMethod(IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhPutValue(IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhPutRef(IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhGetValue(LPCWSTR szIdentifier, void * pResult, IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhInvoke(int invokeType, VARTYPE returnType, VARIANT * pvResult, IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhInvokeArray(int invokeType, VARIANT * pvResult, UINT cArgs, IDispatch * pDisp, LPCOLESTR szMember, VARIANT * pArgs);
HRESULT dhCallMethodV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhPutValueV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhPutRefV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhGetValueV(LPCWSTR szIdentifier, void * pResult, IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhInvokeV(int invokeType, VARTYPE returnType, VARIANT * pvResult, IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhAutoWrap(int invokeType, VARIANT * pvResult, IDispatch * pDisp, LPCOLESTR szMember, UINT cArgs, ...);
HRESULT dhParseProperties(IDispatch * pDisp, LPCWSTR szProperties, UINT * lpcPropsSet);
HRESULT dhEnumBegin(IEnumVARIANT ** ppEnum, IDispatch * pDisp, LPCOLESTR szMember, ...);
HRESULT dhEnumBeginV(IEnumVARIANT ** ppEnum, IDispatch * pDisp, LPCOLESTR szMember, va_list * marker);
HRESULT dhEnumNextObject(IEnumVARIANT * pEnum, IDispatch ** ppDisp);
HRESULT dhEnumNextVariant(IEnumVARIANT * pEnum, VARIANT * pvResult);
HRESULT dhInitializeImp(BOOL bInitializeCOM, BOOL bUnicode);
void dhUninitialize(BOOL bUninitializeCOM);
#define dhInitializeA(bInitializeCOM) dhInitializeImp(bInitializeCOM, FALSE)
#define dhInitializeW(bInitializeCOM) dhInitializeImp(bInitializeCOM, TRUE)
#ifdef UNICODE
#define dhInitialize dhInitializeW
#else
#define dhInitialize dhInitializeA
#endif
#define AutoWrap dhAutoWrap
#define DISPATCH_OBJ(objName) IDispatch * objName = NULL
#define dhFreeString(string) SysFreeString((BSTR) string)
#ifndef SAFE_RELEASE
#ifdef __cplusplus
#define SAFE_RELEASE(pObj) { if (pObj) { (pObj)->Release(); (pObj) = NULL; } }
#else
#define SAFE_RELEASE(pObj) { if (pObj) { (pObj)->lpVtbl->Release(pObj); (pObj) = NULL; } }
#endif
#endif
#define SAFE_FREE_STRING(string) { dhFreeString(string); (string) = NULL; }
/* ===================================================================== */
#ifndef DISPHELPER_NO_WITH
#define WITH0(objName, pDisp, szMember) { \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember))) {
#define WITH1(objName, pDisp, szMember, arg1) { \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1))) {
#define WITH2(objName, pDisp, szMember, arg1, arg2) { \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2))) {
#define WITH3(objName, pDisp, szMember, arg1, arg2, arg3) { \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2, arg3))) {
#define WITH4(objName, pDisp, szMember, arg1, arg2, arg3, arg4) { \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2, arg3, arg4))) {
#define WITH WITH0
#define ON_WITH_ERROR(objName) } else {
#define END_WITH(objName) } SAFE_RELEASE(objName); }
#endif /* ----- DISPHELPER_NO_WITH ----- */
/* ===================================================================== */
#ifndef DISPHELPER_NO_FOR_EACH
#define FOR_EACH0(objName, pDisp, szMember) { \
IEnumVARIANT * xx_pEnum_xx = NULL; \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember))) { \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#define FOR_EACH1(objName, pDisp, szMember, arg1) { \
IEnumVARIANT * xx_pEnum_xx = NULL; \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1))) { \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#define FOR_EACH2(objName, pDisp, szMember, arg1, arg2) { \
IEnumVARIANT * xx_pEnum_xx = NULL; \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2))) { \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#define FOR_EACH3(objName, pDisp, szMember, arg1, arg2, arg3) { \
IEnumVARIANT * xx_pEnum_xx = NULL; \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2, arg3))) { \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#define FOR_EACH4(objName, pDisp, szMember, arg1, arg2, arg3, arg4) { \
IEnumVARIANT * xx_pEnum_xx = NULL; \
DISPATCH_OBJ(objName); \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2, arg3, arg4))) { \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#define FOR_EACH FOR_EACH0
#define ON_FOR_EACH_ERROR(objName) SAFE_RELEASE(objName); }} else {{
#define NEXT(objName) SAFE_RELEASE(objName); }} SAFE_RELEASE(objName); SAFE_RELEASE(xx_pEnum_xx); }
#endif /* ----- DISPHELPER_NO_FOR_EACH ----- */
/* ===================================================================== */
#ifndef DISPHELPER_NO_EXCEPTIONS
/* Structure to store a DispHelper exception */
typedef struct tagDH_EXCEPTION
{
LPCWSTR szInitialFunction;
LPCWSTR szErrorFunction;
HRESULT hr;
WCHAR szMember[64];
WCHAR szCompleteMember[256];
UINT swCode;
LPWSTR szDescription;
LPWSTR szSource;
LPWSTR szHelpFile;
DWORD dwHelpContext;
UINT iArgError;
BOOL bDispatchError;
#ifdef DISPHELPER_INTERNAL_BUILD
BOOL bOld;
#endif
} DH_EXCEPTION, * PDH_EXCEPTION;
typedef void (*DH_EXCEPTION_CALLBACK) (PDH_EXCEPTION);
/* Structure to store exception options. */
typedef struct tagDH_EXCEPTION_OPTIONS
{
HWND hwnd;
LPCWSTR szAppName;
BOOL bShowExceptions;
BOOL bDisableRecordExceptions;
DH_EXCEPTION_CALLBACK pfnExceptionCallback;
} DH_EXCEPTION_OPTIONS, * PDH_EXCEPTION_OPTIONS;
/* Functions to manipulate global exception options */
HRESULT dhToggleExceptions(BOOL bShow);
HRESULT dhSetExceptionOptions(PDH_EXCEPTION_OPTIONS pExceptionOptions);
HRESULT dhGetExceptionOptions(PDH_EXCEPTION_OPTIONS pExceptionOptions);
/* Functions to show an exception, format an exception into a string
* and get a copy of the last exception */
HRESULT dhShowException(PDH_EXCEPTION pException);
HRESULT dhGetLastException(PDH_EXCEPTION * pException);
HRESULT dhFormatExceptionW(PDH_EXCEPTION pException, LPWSTR szBuffer, UINT cchBufferSize, BOOL bFixedFont);
HRESULT dhFormatExceptionA(PDH_EXCEPTION pException, LPSTR szBuffer, UINT cchBufferSize, BOOL bFixedFont);
#ifdef UNICODE
#define dhFormatException dhFormatExceptionW
#else
#define dhFormatException dhFormatExceptionA
#endif
#ifdef DISPHELPER_INTERNAL_BUILD
void dhEnter(void);
HRESULT dhExitEx(HRESULT hr, BOOL bDispatchError, LPCWSTR szMember, LPCWSTR szCompleteMember, EXCEPINFO * pExcepInfo, UINT iArgError, LPCWSTR szFunctionName);
void dhCleanupThreadException(void);
#define DH_ENTER(szFunctionName) static LPCWSTR xx_szFunctionName_xx = szFunctionName; \
dhEnter()
#define DH_EXITEX(hr, bDispatchError, szMember, szCompleteMember, pExcepInfo, iArgError) \
dhExitEx(hr, bDispatchError, szMember, szCompleteMember, pExcepInfo, iArgError, xx_szFunctionName_xx)
#define DH_EXIT(hr, szCompleteMember) DH_EXITEX(hr, FALSE, NULL, szCompleteMember, NULL, 0)
#endif /* ----- DISPHELPER_INTERNAL_BUILD ----- */
#else /* ----- DISPHELPER_NO_EXCEPTIONS ----- */
/* These macros define out calls to selected exception functions */
#define dhToggleExceptions(bShow) (E_NOTIMPL)
#define dhSetExceptionOptions(pExcepOptions) (E_NOTIMPL)
#ifdef DISPHELPER_INTERNAL_BUILD
#define DH_ENTER(szFunctionName)
#define DH_EXITEX(hr, bDispatchError, szMember, szCompleteMember, pExcepInfo, iArgError) \
(((hr == DISP_E_EXCEPTION && pExcepInfo) ? \
(SysFreeString(((EXCEPINFO *)(pExcepInfo))->bstrSource), \
SysFreeString(((EXCEPINFO *)(pExcepInfo))->bstrDescription), \
SysFreeString(((EXCEPINFO *)(pExcepInfo))->bstrHelpFile), 0) : (0)), hr)
#define DH_EXIT(hr, szCompleteMember)(hr)
#endif
#endif /* ----- DISPHELPER_NO_EXCEPTIONS ----- */
/* ===================================================================== */
#ifdef DISPHELPER_INTERNAL_BUILD
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
/* Macro to include or lose debug code. */
#ifdef DEBUG
#define DBG_CODE(code) code
#else
#define DBG_CODE(code)
#endif
/* Are we in unicode mode? */
extern BOOL dh_g_bIsUnicodeMode;
/* Number of objects in an array */
#undef ARRAYSIZE
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/* Maximum number of arguments for a member */
#define DH_MAX_ARGS 25
/* Maximum length of a member string */
#define DH_MAX_MEMBER 512
/* This macro is missing from Dev-Cpp/Mingw */
#ifndef V_UI4
#define V_UI4(X) V_UNION(X, ulVal)
#endif
/* Macro to notify programmer of invalid identifier in debug mode. */
#define DEBUG_NOTIFY_INVALID_IDENTIFIER(chIdentifier) \
DBG_CODE( { \
char buf[256]; \
sprintf(buf,"DEBUG: The format string or return identifier contained the invalid identifier '%c'.\n" \
"The valid identifiers are \"d/u/e/b/v/B/S/s/T/o/O/t/W/D/f/m\".\n" \
"Each %% character should be followed by a valid identifier.\n" \
"Identifiers are case sensitive.", (chIdentifier)); \
MessageBoxA(NULL, buf, "DEBUG: Invalid Format Identifier", MB_ICONSTOP); \
} )
#ifdef _MSC_VER
#pragma warning(disable : 4706) /* Assignment in conditional expression */
#endif
#ifndef DISPHELPER_NO_PRAGMA_LIB
#ifdef __LCC__
#pragma lib <ole32.lib>
#pragma lib <oleaut32.lib>
#pragma lib <uuid.lib>
#endif
#endif
#endif /* ----- DISPHELPER_INTERNAL_BUILD ----- */
#ifndef DISPHELPER_NO_PRAGMA_LIB
#if defined(_MSC_VER) || defined(__BORLANDC__)
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "uuid.lib")
#endif
#endif
#ifdef __cplusplus
}
#endif
/* ===================================================================== */
#if defined(__cplusplus) && !defined(DISPHELPER_NO_CPP_EXTENSIONS)
#include <iostream>
#include <string>
#ifdef _MSC_VER
#pragma warning( disable : 4290 ) /* throw() specification ignored */
#endif
#ifndef DISPHELPER_USE_MS_SMART_PTR
template <class T>
class CDhComPtr
{
public:
CDhComPtr() throw() : m_pInterface (NULL) {}
CDhComPtr(T* pInterface) throw() : m_pInterface (pInterface)
{
if (m_pInterface) m_pInterface->AddRef();
}
CDhComPtr(const CDhComPtr& original) throw() : m_pInterface (original.m_pInterface)
{
if (m_pInterface) m_pInterface->AddRef();
}
~CDhComPtr() throw()
{
Dispose();
}
void Dispose() throw()
{
if (m_pInterface)
{
m_pInterface->Release();
m_pInterface = NULL;
}
}
T* Detach() throw()
{
T* temp = m_pInterface;
m_pInterface = NULL;
return temp;
}
inline operator T*() const throw()
{
return m_pInterface;
}
T** operator&() throw()
{
Dispose();
return &m_pInterface;
}
T* operator->() const throw(HRESULT)
{
if (!m_pInterface) throw E_POINTER;
return m_pInterface;
}
CDhComPtr& operator=(T* pInterface) throw()
{
if (m_pInterface != pInterface)
{
T* pOldInterface = m_pInterface;
m_pInterface = pInterface;
if (m_pInterface) m_pInterface->AddRef();
if (pOldInterface) pOldInterface->Release();
}
return *this;
}
CDhComPtr& operator=(const int null) throw(HRESULT)
{
if (null != 0) throw(E_POINTER);
return operator=((T*) NULL);
}
CDhComPtr& operator=(const CDhComPtr& rhs) throw()
{
return operator=(rhs.m_pInterface);
}
private:
T* m_pInterface;
};
typedef CDhComPtr<IDispatch> CDispPtr;
typedef CDhComPtr<IEnumVARIANT> CEnumPtr;
typedef CDhComPtr<IUnknown> CUnknownPtr;
#else /* DISPHELPER_USE_MS_SMART_PTR */
#include <comdef.h>
typedef IDispatchPtr CDispPtr;
typedef IEnumVARIANTPtr CEnumPtr;
typedef IUnknownPtr CUnknownPtr;
#endif /* DISPHELPER_USE_MS_SMART_PTR */
/* ===================================================================== */
template <class T>
class CDhStringTemplate
{
public:
CDhStringTemplate() throw() : m_strptr (NULL) {}
CDhStringTemplate(const CDhStringTemplate& original) throw()
{
Copy(original.m_strptr);
}
CDhStringTemplate(const int null) throw(HRESULT) : m_strptr (NULL)
{
if (null != 0) throw(E_POINTER);
}
~CDhStringTemplate() throw()
{
Dispose();
}
void Dispose() throw()
{
dhFreeString(m_strptr);
m_strptr = NULL;
}
T* Detach() throw()
{
T* temp = m_strptr;
m_strptr = NULL;
return temp;
}
T** operator&() throw()
{
Dispose();
return &m_strptr;
}
inline operator T*() const throw()
{
return m_strptr;
}
inline T& operator[](int nIndex) const throw()
{
return m_strptr[nIndex];
}
CDhStringTemplate& operator=(const CDhStringTemplate& rhs)
{
if (m_strptr != rhs.m_strptr)
{
T* temp = m_strptr;
Copy(rhs.m_strptr);
dhFreeString(temp);
}
return *this;
}
CDhStringTemplate& operator=(const int null) throw(HRESULT)
{
if (null != 0) throw(E_POINTER);
Dispose();
return *this;
}
private:
void Copy(const T* rhs)
{
if (rhs == NULL)
{
m_strptr = NULL;
}
else if (sizeof(T) == sizeof(CHAR))
{
m_strptr = (T*) SysAllocStringByteLen((LPCSTR) rhs, SysStringByteLen((BSTR) rhs));
}
else
{
m_strptr = (T*) SysAllocStringLen((OLECHAR *) rhs, SysStringLen((BSTR) rhs));
}
}
T* m_strptr;
};
typedef CDhStringTemplate<CHAR> CDhStringA; /* Ansi string - LPSTR */
typedef CDhStringTemplate<WCHAR> CDhStringW; /* Unicode string - LPWSTR */
typedef CDhStringTemplate<OLECHAR> CDhStringB; /* Unicode bstring - BSTR */
typedef CDhStringTemplate<TCHAR> CDhStringT; /* T string - LPTSTR */
typedef CDhStringTemplate<TCHAR> CDhString; /* T string - LPTSTR */
inline std::ostream& operator<<(std::ostream& os, const CDhStringA& s)
{
return os << (s ? s : (char*) "(null)");
}
//inline std::wostream& operator<<(std::wostream& os, const CDhStringW& s)
//{
// return os << (s ? s : (wchar_t*) L"(null)");
//}
/* ===================================================================== */
class CDhInitialize
{
public:
CDhInitialize(const BOOL bInitCom = TRUE) throw() : m_bInitCom (bInitCom)
{
dhInitialize(m_bInitCom);
}
~CDhInitialize() throw()
{
dhUninitialize(m_bInitCom);
}
private:
BOOL m_bInitCom;
};
/* ===================================================================== */
#ifndef DISPHELPER_NO_EXCEPTIONS
class dhThrowFunctions
{
public:
static void throw_string() throw(std::string)
{
CHAR szMessage[512];
dhFormatExceptionA(NULL, szMessage, sizeof(szMessage)/sizeof(szMessage[0]), TRUE);
throw std::string(szMessage);
}
static void throw_wstring() throw(std::wstring)
{
WCHAR szMessage[512];
dhFormatExceptionW(NULL, szMessage, sizeof(szMessage)/sizeof(szMessage[0]), TRUE);
throw std::wstring(szMessage);
}
static void throw_dhexception() throw(PDH_EXCEPTION)
{
PDH_EXCEPTION pException = NULL;
dhGetLastException(&pException);
throw pException;
}
};
#endif /* DISPHELPER_NO_EXCEPTIONS */
/* ===================================================================== */
#ifndef DISPHELPER_NO_EXCEPTIONS
inline bool dhIfFailThrowString(HRESULT hr) throw(std::string)
{
if (FAILED(hr)) dhThrowFunctions::throw_string();
return true;
}
inline bool dhIfFailThrowWString(HRESULT hr) throw(std::wstring)
{
if (FAILED(hr)) dhThrowFunctions::throw_wstring();
return true;
}
inline bool dhIfFailThrowDhException(HRESULT hr) throw(PDH_EXCEPTION)
{
if (FAILED(hr)) dhThrowFunctions::throw_dhexception();
return true;
}
#define dhCheck dhIfFailThrowString
#endif /* DISPHELPER_NO_EXCEPTIONS */
/* ===================================================================== */
#ifndef DISPHELPER_NO_WITH
#undef WITH0
#define WITH0(objName, pDisp, szMember) { \
CDispPtr objName; \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember))) {
#undef WITH1
#define WITH1(objName, pDisp, szMember, arg1) { \
CDispPtr objName; \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1))) {
#undef WITH2
#define WITH2(objName, pDisp, szMember, arg1, arg2) { \
CDispPtr objName; \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2))) {
#undef WITH3
#define WITH3(objName, pDisp, szMember, arg1, arg2, arg3) { \
CDispPtr objName; \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2, arg3))) {
#undef WITH4
#define WITH4(objName, pDisp, szMember, arg1, arg2, arg3, arg4) { \
CDispPtr objName; \
if (SUCCEEDED(dhGetValue(L"%o", &objName, pDisp, szMember, arg1, arg2, arg3, arg4))) {
#undef ON_WITH_ERROR
#define ON_WITH_ERROR(objName) } else {
#undef END_WITH
#define END_WITH(objName) }}
#define END_WITH_THROW(objName) } else { dhThrowFunctions::throw_string(); }}
#endif /* DISPHELPER_NO_WITH */
/* ===================================================================== */
#ifndef DISPHELPER_NO_FOR_EACH
#undef FOR_EACH0
#define FOR_EACH0(objName, pDisp, szMember) { \
CEnumPtr xx_pEnum_xx; \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember))) { \
CDispPtr objName; \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#undef FOR_EACH1
#define FOR_EACH1(objName, pDisp, szMember, arg1) { \
CEnumPtr xx_pEnum_xx; \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1))) { \
CDispPtr objName; \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#undef FOR_EACH2
#define FOR_EACH2(objName, pDisp, szMember, arg1, arg2) { \
CEnumPtr xx_pEnum_xx; \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2))) { \
CDispPtr objName; \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#undef FOR_EACH3
#define FOR_EACH3(objName, pDisp, szMember, arg1, arg2, arg3) { \
CEnumPtr xx_pEnum_xx; \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2, arg3))) { \
CDispPtr objName; \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#undef FOR_EACH4
#define FOR_EACH4(objName, pDisp, szMember, arg1, arg2, arg3, arg4) { \
CEnumPtr xx_pEnum_xx; \
if (SUCCEEDED(dhEnumBegin(&xx_pEnum_xx, pDisp, szMember, arg1, arg2, arg3, arg4))) { \
CDispPtr objName; \
while (dhEnumNextObject(xx_pEnum_xx, &objName) == NOERROR) {
#undef ON_FOR_EACH_ERROR
#define ON_FOR_EACH_ERROR(objName) }} else {{
#undef NEXT
#define NEXT(objName) }}}
#define NEXT_THROW(objName) }} else { dhThrowFunctions::throw_string(); }}
#endif /* DISPHELPER_NO_FOR_EACH */
#ifdef _MSC_VER
#pragma warning( default : 4290 )
#endif
#endif /* defined(__cplusplus) && !defined(DISPHELPER_NO_CPP_EXTENSIONS) */
#endif /* ----- DISPHELPER_H_INCLUDED ----- */