Ignore ReinitializeDevice and DeviceCommunicationControl service password (#518)
* Fix device object ReinitializeDevice service handling examples of no-password in the device. Add unit testing of device object ReinitializeDevice service. Add API for setting ReinitializeDevice device object password. * Fix DeviceCommunicationControl service handling example of no-password in the device. --------- Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
@@ -67,12 +67,11 @@ static struct my_object_functions {
|
||||
read_property_function Object_Read_Property;
|
||||
write_property_function Object_Write_Property;
|
||||
rpm_property_lists_function Object_RPM_List;
|
||||
} Object_Table[] = {
|
||||
{ OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number,
|
||||
Device_Object_Name, Device_Read_Property_Local,
|
||||
Device_Write_Property_Local, Device_Property_Lists },
|
||||
} Object_Table[] = { { OBJECT_DEVICE, NULL, /* don't init - recursive! */
|
||||
Device_Count, Device_Index_To_Instance,
|
||||
Device_Valid_Object_Instance_Number,
|
||||
Device_Object_Name, Device_Read_Property_Local,
|
||||
Device_Write_Property_Local, Device_Property_Lists },
|
||||
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
|
||||
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
|
||||
Analog_Input_Object_Name, Analog_Input_Read_Property, NULL,
|
||||
@@ -161,8 +160,7 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
#if (BACNET_PROTOCOL_REVISION >= 14)
|
||||
if ((int)rpdata->object_property == PROP_PROPERTY_LIST) {
|
||||
Device_Objects_Property_List(rpdata->object_type,
|
||||
rpdata->object_instance,
|
||||
&property_list);
|
||||
rpdata->object_instance, &property_list);
|
||||
apdu_len = property_list_encode(rpdata,
|
||||
property_list.Required.pList,
|
||||
property_list.Optional.pList,
|
||||
@@ -306,12 +304,64 @@ bool Device_Object_Name(
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the ReinitializeDevice password
|
||||
*
|
||||
* The password shall be a null terminated C string of up to
|
||||
* 20 ASCII characters for those devices that require the password.
|
||||
*
|
||||
* For those devices that do not require a password, set to NULL or
|
||||
* point to a zero length C string (null terminated).
|
||||
*
|
||||
* @param the ReinitializeDevice password; can be NULL or empty string
|
||||
*/
|
||||
bool Device_Reinitialize_Password_Set(const char *password)
|
||||
{
|
||||
Reinit_Password = password;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Commands a Device re-initialization, to a given state.
|
||||
* The request's password must match for the operation to succeed.
|
||||
* This implementation provides a framework, but doesn't
|
||||
* actually *DO* anything.
|
||||
* @note You could use a mix of states and passwords to multiple outcomes.
|
||||
* @note You probably want to restart *after* the simple ack has been sent
|
||||
* from the return handler, so just set a local flag here.
|
||||
* @ingroup ObjIntf
|
||||
*
|
||||
* @param rd_data [in,out] The information from the RD request.
|
||||
* On failure, the error class and code will be set.
|
||||
* @return True if succeeds (password is correct), else False.
|
||||
*/
|
||||
bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
{
|
||||
bool status = false;
|
||||
bool password_success = false;
|
||||
|
||||
/* Note: you could use a mix of state and password to multiple things */
|
||||
if (characterstring_ansi_same(&rd_data->password, Reinit_Password)) {
|
||||
/* From 16.4.1.1.2 Password
|
||||
This optional parameter shall be a CharacterString of up to
|
||||
20 characters. For those devices that require the password as a
|
||||
protection, the service request shall be denied if the parameter
|
||||
is absent or if the password is incorrect. For those devices that
|
||||
do not require a password, this parameter shall be ignored.*/
|
||||
if (Reinit_Password && strlen(Reinit_Password) > 0) {
|
||||
if (characterstring_length(&rd_data->password) > 20) {
|
||||
rd_data->error_class = ERROR_CLASS_SERVICES;
|
||||
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
|
||||
} else if (characterstring_ansi_same(
|
||||
&rd_data->password, Reinit_Password)) {
|
||||
password_success = true;
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
|
||||
}
|
||||
} else {
|
||||
password_success = true;
|
||||
}
|
||||
if (password_success) {
|
||||
switch (rd_data->state) {
|
||||
case BACNET_REINIT_COLDSTART:
|
||||
case BACNET_REINIT_WARMSTART:
|
||||
@@ -341,9 +391,6 @@ bool Device_Reinitialize(BACNET_REINITIALIZE_DEVICE_DATA *rd_data)
|
||||
rd_data->error_code = ERROR_CODE_PARAMETER_OUT_OF_RANGE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
rd_data->error_class = ERROR_CLASS_SECURITY;
|
||||
rd_data->error_code = ERROR_CODE_PASSWORD_FAILURE;
|
||||
}
|
||||
|
||||
return status;
|
||||
@@ -695,9 +742,8 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
|
||||
case PROP_OBJECT_LIST:
|
||||
count = Device_Object_List_Count();
|
||||
apdu_len = bacnet_array_encode(rpdata->object_instance,
|
||||
rpdata->array_index,
|
||||
Device_Object_List_Element_Encode,
|
||||
count, apdu, apdu_max);
|
||||
rpdata->array_index, Device_Object_List_Element_Encode, count,
|
||||
apdu, apdu_max);
|
||||
if (apdu_len == BACNET_STATUS_ABORT) {
|
||||
rpdata->error_code =
|
||||
ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED;
|
||||
|
||||
Reference in New Issue
Block a user