From 058cc4f4dce21260bf99a2a795f2a2d8d3095023 Mon Sep 17 00:00:00 2001
From: Claudio Scafuri <claudio.scafuri@elettra.eu>
Date: Fri, 2 Oct 2020 11:50:37 +0200
Subject: [PATCH] enbedded privilege checkings methods

---
 src/SupervisedID.cpp             | 167 +++++++++++++++++++++++++++++--
 src/SupervisedID.h               |  33 +++++-
 src/SupervisedID.xmi             |  15 +--
 src/SupervisedIDClass.cpp        |  45 +++++++--
 src/SupervisedIDClass.h          |   1 +
 src/SupervisedIDStateMachine.cpp |  12 ++-
 6 files changed, 247 insertions(+), 26 deletions(-)

diff --git a/src/SupervisedID.cpp b/src/SupervisedID.cpp
index c5aa89f..15b77d2 100644
--- a/src/SupervisedID.cpp
+++ b/src/SupervisedID.cpp
@@ -1,5 +1,5 @@
 /*----- PROTECTED REGION ID(SupervisedID.cpp) ENABLED START -----*/
-static const char *RcsId = "$Id: SupervisedID.cpp,v 1.2 2014-04-14 14:51:54 claudio Exp $";
+
 //=============================================================================
 //
 // file :        SupervisedID.cpp
@@ -142,16 +142,87 @@ void SupervisedID::init_device()
 	
 	/*----- PROTECTED REGION END -----*/	//	SupervisedID::init_device_before
 	
-	//	No device property to be read from database
-	
 
+	//	Get the device properties from database
+	get_device_property();
+	
 	/*----- PROTECTED REGION ID(SupervisedID::init_device) ENABLED START -----*/
 
 	//	Initialize device
-
+	//init hostMap from hostPriviliges
+	{
+		vector<string>::const_iterator i;
+		for (i = hostPrivileges.begin(); i != hostPrivileges.end(); i++) {
+			int pos = (*i).find(':');
+			if (pos <= 0) {
+				ERROR_STREAM
+				<< "SupervisedID::init()  hostPrivileges syntax error "
+				<< (*i) << endl;
+			} else {
+				string h = (*i).substr(0, pos);
+				string val = (*i).substr(pos + 1);
+				int valint = atoi(val.c_str());
+				DEBUG_STREAM << "host: " << h << " privilege: " << valint
+						<< endl;
+				pair<string, int> mypair(h, valint);
+				hostMap.insert(mypair);
+			}
+		}
+	}
 	/*----- PROTECTED REGION END -----*/	//	SupervisedID::init_device
 }
 
+//--------------------------------------------------------
+/**
+ *	Method      : SupervisedID::get_device_property()
+ *	Description : Read database to initialize property data members.
+ */
+//--------------------------------------------------------
+void SupervisedID::get_device_property()
+{
+	/*----- PROTECTED REGION ID(SupervisedID::get_device_property_before) ENABLED START -----*/
+	
+	//	Initialize property data members
+	
+	/*----- PROTECTED REGION END -----*/	//	SupervisedID::get_device_property_before
+
+
+	//	Read device properties from database.
+	Tango::DbData	dev_prop;
+	dev_prop.push_back(Tango::DbDatum("HostPrivileges"));
+
+	//	is there at least one property to be read ?
+	if (dev_prop.size()>0)
+	{
+		//	Call database and extract values
+		if (Tango::Util::instance()->_UseDb==true)
+			get_db_device()->get_property(dev_prop);
+	
+		//	get instance on SupervisedIDClass to get class property
+		Tango::DbDatum	def_prop, cl_prop;
+		SupervisedIDClass	*ds_class =
+			(static_cast<SupervisedIDClass *>(get_device_class()));
+		int	i = -1;
+
+		//	Try to initialize HostPrivileges from class property
+		cl_prop = ds_class->get_class_property(dev_prop[++i].name);
+		if (cl_prop.is_empty()==false)	cl_prop  >>  hostPrivileges;
+		else {
+			//	Try to initialize HostPrivileges from default device value
+			def_prop = ds_class->get_default_device_property(dev_prop[i].name);
+			if (def_prop.is_empty()==false)	def_prop  >>  hostPrivileges;
+		}
+		//	And try to extract HostPrivileges value from database
+		if (dev_prop[i].is_empty()==false)	dev_prop[i]  >>  hostPrivileges;
+
+	}
+
+	/*----- PROTECTED REGION ID(SupervisedID::get_device_property_after) ENABLED START -----*/
+	
+	//	Check device property data members init
+	
+	/*----- PROTECTED REGION END -----*/	//	SupervisedID::get_device_property_after
+}
 
 //--------------------------------------------------------
 /**
@@ -161,7 +232,7 @@ void SupervisedID::init_device()
 //--------------------------------------------------------
 void SupervisedID::always_executed_hook()
 {
-	INFO_STREAM << "SupervisedID::always_executed_hook()  " << device_name << endl;
+	DEBUG_STREAM << "SupervisedID::always_executed_hook()  " << device_name << endl;
 	/*----- PROTECTED REGION ID(SupervisedID::always_executed_hook) ENABLED START -----*/
 
 	//	code always executed before all requests
@@ -217,10 +288,94 @@ void SupervisedID::add_dynamic_attributes()
 	/*----- PROTECTED REGION END -----*/	//	SupervisedID::add_dynamic_attributes
 }
 
+//--------------------------------------------------------
+/**
+ *	Method      : SupervisedID::add_dynamic_commands()
+ *	Description : Create the dynamic commands if any
+ *                for specified device.
+ */
+//--------------------------------------------------------
+void SupervisedID::add_dynamic_commands()
+{
+	/*----- PROTECTED REGION ID(SupervisedID::add_dynamic_commands) ENABLED START -----*/
+	
+	//	Add your own code to create and add dynamic commands if any
+	
+	/*----- PROTECTED REGION END -----*/	//	SupervisedID::add_dynamic_commands
+}
 
 /*----- PROTECTED REGION ID(SupervisedID::namespace_ending) ENABLED START -----*/
 
 	//	Additional Methods
-
+//-------------------------------------------------------------------------------
+    /**
+	 * assign privileges elevel based on host name from which the call is generated
+	 * PRIVILEGED : can change the enable bit and set gap/tapering
+	 * AUTHORIZED : can set gap/tapering when enabled
+	 * NORMAL     : can only read;
+	 */
+int SupervisedID::caller_privileges(void)
+{
+	//if no privileges are configured, run unimpeded
+	if(hostMap.size() == 0)return PRIVILEGED;
+
+	Tango::DevVarStringArray blackbox = black_box(1)[0];
+	string last_msg(blackbox[0].in());
+	string::size_type loc = last_msg.find( " requested from ", 0 );
+	if( loc != string::npos )
+	{
+		clientAddress = last_msg.substr(loc + strlen(" requested from "));
+		loc=clientAddress.find(" ",0);
+		clientAddress =clientAddress.substr(0,loc);
+		INFO_STREAM<<"checking call from "<<clientAddress<<endl;
+		//         std::set<std::string> client_ips;
+		//         get_ips_from_host(clientAddress, client_ips);
+		//
+		//         for (std::set<std::string>::const_iterator it = client_ips.begin(); it != client_ips.end(); ++it )
+		//         {
+		//             if (std::find(allowed_ips.begin(), allowed_ips.end(), *it) != allowed_ips.end())
+		//                 return;  // found the IP in the allowed list of IPs
+		//         }
+		map<string,int>::iterator it;
+		it=hostMap.find(clientAddress);
+		if (it == hostMap.end()) {
+			INFO_STREAM << clientAddress<< " host not foud" << endl;
+			return NORMAL;
+		}
+		else {
+			INFO_STREAM << "host: "<< clientAddress<< " privilges="<< it->second << endl;
+			return it->second;
+		}
+
+	}
+	else
+	{
+		WARN_STREAM << "Cannot extract client IP or hostname from tango blackbox, denying access.";
+		clientAddress="";
+		return NORMAL; //do not grant special privileges
+	}
+	return NORMAL; //do not grant special privilege - but we should NOT arrive at this line
+}
+//--------------------------------------------------------------------
+/**
+	 * check privileges level based on host name from which the call is generated
+	 * formats warning/  error messages and throw exception in case of vilotaions
+	 * privilege levels:
+	 * PRIVILEGED : can change the enable bit and set gap/tapering
+	 * AUTHORIZED : can set gap/tapering when enabled
+	 * NORMAL     : can only read;
+	 */
+
+int SupervisedID::check_privileges(int level, string msg)
+{
+	int priv=caller_privileges();
+	if (priv < level){
+		INFO_STREAM << msg << " from "<< clientAddress <<" REJECTED"<<endl;
+		TangoSys_OMemStream o;
+		o << msg << " from "<< clientAddress <<" REJECTED"<<ends;
+		Tango::Except::throw_exception((const char *)"Host not allowed",o.str(),msg);
+	}
+	return priv;
+}
 	/*----- PROTECTED REGION END -----*/	//	SupervisedID::namespace_ending
 } //	namespace
diff --git a/src/SupervisedID.h b/src/SupervisedID.h
index 6ad1865..d794560 100644
--- a/src/SupervisedID.h
+++ b/src/SupervisedID.h
@@ -36,7 +36,10 @@
 
 
 #include <tango.h>
-
+#include <map>
+#define PRIVILEGED 2
+#define AUTHORIZED 1
+#define NORMAL     0
 /*----- PROTECTED REGION END -----*/	//	SupervisedID.h
 
 /**
@@ -60,9 +63,22 @@ class SupervisedID : public TANGO_BASE_CLASS
 /*----- PROTECTED REGION ID(SupervisedID::Data Members) ENABLED START -----*/
 
 	//		Add your own data members
+protected:
+    int caller_privileges(void);
+    bool is_privileged; //true is the caller has all privileges - must be handled in alawys_executed
+    string clientAddress;
+    map<string,int> hostMap;
+    int check_privileges(int, string); //check privileges , emits diagnostics and throw exception, returns actual privileges
 
 	/*----- PROTECTED REGION END -----*/	//	SupervisedID::Data Members
 
+//	Device property data members
+public:
+	//	HostPrivileges:	list of host:privileges
+	//  host:2   host is privileged can read and write and change limits and change permission
+	//  host:1  host is authorized can read and write when permitted
+	//  host:0 host can only read
+	vector<string>	hostPrivileges;
 
 //	Attribute data members
 public:
@@ -93,7 +109,7 @@ public:
 	SupervisedID(Tango::DeviceClass *cl,const char *s,const char *d);
 	/**
 	 * The device object destructor.
-	 */	
+	 */
 	~SupervisedID() {delete_device();};
 
 
@@ -107,6 +123,10 @@ public:
 	 *	Initialize the device
 	 */
 	virtual void init_device();
+	/*
+	 *	Read the device properties from database
+	 */
+	void get_device_property();
 	/*
 	 *	Always executed method before execution command method.
 	 */
@@ -172,10 +192,19 @@ public:
 
 
 
+
 //	Command related methods
 public:
 
 
+	//--------------------------------------------------------
+	/**
+	 *	Method      : SupervisedID::add_dynamic_commands()
+	 *	Description : Add dynamic commands if any.
+	 */
+	//--------------------------------------------------------
+	void add_dynamic_commands();
+
 /*----- PROTECTED REGION ID(SupervisedID::Additional Method prototypes) ENABLED START -----*/
 
 	//	Additional Method prototypes
diff --git a/src/SupervisedID.xmi b/src/SupervisedID.xmi
index cc61afb..ea06ef1 100644
--- a/src/SupervisedID.xmi
+++ b/src/SupervisedID.xmi
@@ -1,10 +1,14 @@
 <?xml version="1.0" encoding="ASCII"?>
 <pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl">
-  <classes name="SupervisedID" pogoRevision="8.3">
-    <description description="This abstract class incapsulates the common interface for insertion devices used&#xA;under ID supervisor. The &quot;supervisor&quot; can inhibi/allow the operations on the insertion device&#xA;and impose limits on the permited range." title="Supervised ID: common interface for supervised insertion devices" sourcePath="/home/claudio/devel/AbstractClasses7/SupervisedID" language="Cpp" filestogenerate="XMI   file,Code files" hasMandatoryProperty="false" hasConcreteProperty="false" hasAbstractCommand="false" hasAbstractAttribute="true">
+  <classes name="SupervisedID" pogoRevision="9.6">
+    <description description="This abstract class incapsulates the common interface for insertion devices used&#xA;under ID supervisor. The &quot;supervisor&quot; can inhibi/allow the operations on the insertion device&#xA;and impose limits on the permited range." title="Supervised ID: common interface for supervised insertion devices" sourcePath="/home/claudio/src/gitlab/cs/cls/supervisedid/src" language="Cpp" filestogenerate="XMI   file,Code files,Protected Regions" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="true">
       <inheritances classname="Device_4Impl" sourcePath=""/>
       <identification contact="at elettra.trieste.it - claudio.scafuri" author="claudio.scafuri" emailDomain="elettra.trieste.it" classFamily="Controllers" siteSpecific="" platform="All Platforms" bus="Not Applicable" manufacturer="none" reference=""/>
     </description>
+    <deviceProperties name="HostPrivileges" description="list of host:privileges&#xA;host:2   host is privileged can read and write and change limits and change permission&#xA;host:1  host is authorized can read and write when permitted&#xA;host:0 host can only read">
+      <type xsi:type="pogoDsl:StringVectorType"/>
+      <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
+    </deviceProperties>
     <commands name="State" description="This command gets the device state (stored in its &lt;i>device_state&lt;/i> data member) and returns it to the caller." execMethod="dev_state" displayLevel="OPERATOR" polledPeriod="0">
       <argin description="none.">
         <type xsi:type="pogoDsl:VoidType"/>
@@ -52,12 +56,9 @@
     <states name="UNKNOWN" description="Device not working - unknow reason/condition">
       <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
     </states>
-    <states name="RUNNING" description="Device gap is moving">
-      <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
-    </states>
-    <states name="DISABLE" description="Device not remotely operable">
+    <states name="MOVING" description="Device gap is moving">
       <status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
     </states>
-    <preferences docHome="./doc_html" makefileHome="/usr/local/tango-8.1.2.c/share/pogo/preferences"/>
+    <preferences docHome="./doc_html" makefileHome="/usr/local/tango-9.3.3/share/pogo/preferences"/>
   </classes>
 </pogoDsl:PogoSystem>
diff --git a/src/SupervisedIDClass.cpp b/src/SupervisedIDClass.cpp
index 663cb33..d22c427 100644
--- a/src/SupervisedIDClass.cpp
+++ b/src/SupervisedIDClass.cpp
@@ -1,9 +1,4 @@
 /*----- PROTECTED REGION ID(SupervisedIDClass.cpp) ENABLED START -----*/
-static const char *RcsId      = "$Id: SupervisedIDClass.cpp,v 1.2 2014-04-14 14:51:54 claudio Exp $";
-static const char *TagName    = "$Name:  $";
-static const char *CvsPath    = "$Source: /home/cvsadm/cvsroot/AbstractClasses7/SupervisedID/SupervisedIDClass.cpp,v $";
-static const char *SvnPath    = "$HeadURL:  $";
-static const char *HttpServer = "http://www.esrf.eu/computing/cs/tango/tango_doc/ds_doc/";
 //=============================================================================
 //
 // file :        SupervisedIDClass.cpp
@@ -11,7 +6,7 @@ static const char *HttpServer = "http://www.esrf.eu/computing/cs/tango/tango_doc
 // description : C++ source for the SupervisedIDClass. A singleton
 //               class derived from DeviceClass. It implements the
 //               command list and all properties and methods required
-//               by the «name» once per process.
+//               by the �name� once per process.
 //
 // project :     Supervised ID: common interface for supervised insertion devices.
 //
@@ -126,8 +121,8 @@ SupervisedIDClass *SupervisedIDClass::init(const char *name)
 		catch (bad_alloc &)
 		{
 			throw;
-		}		
-	}		
+		}
+	}
 	return _instance;
 }
 
@@ -222,6 +217,19 @@ void SupervisedIDClass::set_default_property()
 	//	Set Default Class Properties
 
 	//	Set Default device Properties
+	prop_name = "HostPrivileges";
+	prop_desc = "list of host:privileges\nhost:2   host is privileged can read and write and change limits and change permission\nhost:1  host is authorized can read and write when permitted\nhost:0 host can only read";
+	prop_def  = "";
+	vect_data.clear();
+	if (prop_def.length()>0)
+	{
+		Tango::DbDatum	data(prop_name);
+		data << vect_data ;
+		dev_def_prop.push_back(data);
+		add_wiz_dev_prop(prop_name, prop_desc,  prop_def);
+	}
+	else
+		add_wiz_dev_prop(prop_name, prop_desc);
 }
 
 //--------------------------------------------------------
@@ -266,6 +274,7 @@ void SupervisedIDClass::attribute_factory(vector<Tango::Attr *> &att_list)
 
 
 
+
 	/*----- PROTECTED REGION ID(SupervisedIDClass::attribute_factory_after) ENABLED START -----*/
 	
 	//	Add your own code
@@ -273,6 +282,26 @@ void SupervisedIDClass::attribute_factory(vector<Tango::Attr *> &att_list)
 	/*----- PROTECTED REGION END -----*/	//	SupervisedIDClass::attribute_factory_after
 }
 //--------------------------------------------------------
+/**
+ *	Method      : SupervisedIDClass::pipe_factory()
+ *	Description : Create the pipe object(s)
+ *                and store them in the pipe list
+ */
+//--------------------------------------------------------
+void SupervisedIDClass::pipe_factory()
+{
+	/*----- PROTECTED REGION ID(SupervisedIDClass::pipe_factory_before) ENABLED START -----*/
+	
+	//	Add your own code
+	
+	/*----- PROTECTED REGION END -----*/	//	SupervisedIDClass::pipe_factory_before
+	/*----- PROTECTED REGION ID(SupervisedIDClass::pipe_factory_after) ENABLED START -----*/
+	
+	//	Add your own code
+	
+	/*----- PROTECTED REGION END -----*/	//	SupervisedIDClass::pipe_factory_after
+}
+//--------------------------------------------------------
 /**
  *	Method      : SupervisedIDClass::command_factory()
  *	Description : Create the command object(s)
diff --git a/src/SupervisedIDClass.h b/src/SupervisedIDClass.h
index 25d7c94..ea5fb64 100644
--- a/src/SupervisedIDClass.h
+++ b/src/SupervisedIDClass.h
@@ -87,6 +87,7 @@ class SupervisedIDClass : public Tango::DeviceClass
 		static SupervisedIDClass *_instance;
 		void command_factory();
 		void attribute_factory(vector<Tango::Attr *> &);
+		void pipe_factory();
 		void write_class_property();
 		void set_default_property();
 		void get_class_property();
diff --git a/src/SupervisedIDStateMachine.cpp b/src/SupervisedIDStateMachine.cpp
index d41f8cf..d9ebf5b 100644
--- a/src/SupervisedIDStateMachine.cpp
+++ b/src/SupervisedIDStateMachine.cpp
@@ -1,5 +1,4 @@
 /*----- PROTECTED REGION ID(SupervisedIDStateMachine.cpp) ENABLED START -----*/
-static const char *RcsId = "$Id: SupervisedIDStateMachine.cpp,v 1.2 2014-04-14 14:52:01 claudio Exp $";
 //=============================================================================
 //
 // file :        SupervisedIDStateMachine.cpp
@@ -45,8 +44,7 @@ static const char *RcsId = "$Id: SupervisedIDStateMachine.cpp,v 1.2 2014-04-14 1
 //  ON       |  Device OK
 //  FAULT    |  Device not working - broken ID
 //  UNKNOWN  |  Device not working - unknow reason/condition
-//  RUNNING  |  Device gap is moving
-//  DISABLE  |  Device not remotely operable
+//  MOVING   |  Device gap is moving
 
 
 namespace SupervisedID_ns
@@ -107,8 +105,16 @@ bool SupervisedID::is_StatRF_allowed(TANGO_UNUSED(Tango::AttReqType type))
 	return true;
 }
 
+
 //=================================================
 //		Commands Allowed Methods
 //=================================================
 
+
+/*----- PROTECTED REGION ID(SupervisedID::SupervisedIDStateAllowed.AdditionalMethods) ENABLED START -----*/
+
+//	Additional Methods
+
+/*----- PROTECTED REGION END -----*/	//	SupervisedID::SupervisedIDStateAllowed.AdditionalMethods
+
 }	//	End of namespace
-- 
GitLab