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:
parent
e602fbb96d
commit
54a0db6509
|
@ -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.
|
|
@ -1,3 +0,0 @@
|
|||
2006-06-20 Esteban Sánchez
|
||||
|
||||
* Initial import.
|
|
@ -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=
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -159,3 +159,4 @@ void
|
|||
Pandora::setPandoraDebug (bool dbg) {
|
||||
pandora_debug = dbg;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,4 +59,4 @@ namespace Pandora {
|
|||
class Pandora_Exception { };
|
||||
}
|
||||
|
||||
#endif /* __BABEL_H__ */
|
||||
#endif /* __PANDORA_H__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,5 @@ namespace Pandora_Strutils {
|
|||
void
|
||||
stringtok (list<string> &l, string const &s,
|
||||
char const * const separators = " \t\n");
|
||||
|
||||
}
|
||||
#endif /* __STRUTILS_H__ */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
/* }}} */
|
|
@ -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;
|
||||
}
|
||||
/* }}} */
|
||||
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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 ();
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 ----- */
|
Loading…
Reference in New Issue