void Service_GetEndpoints(UA_Server *server, const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response) { UA_GetEndpointsResponse_init(response); response->endpointsSize = 1; response->endpoints = UA_alloc(sizeof(UA_EndpointDescription)); if(!response->endpoints) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } if(UA_EndpointDescription_copy(server->endpointDescriptions, response->endpoints) != UA_STATUSCODE_GOOD) { UA_free(response->endpoints); response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; } }
/* * Get the endpoint from the server, where we can call RegisterServer2 (or RegisterServer). * This is normally the endpoint with highest supported encryption mode. * * @param discoveryServerUrl The discovery url from the remote server * @return The endpoint description (which needs to be freed) or NULL */ static UA_EndpointDescription *getRegisterEndpointFromServer(const char *discoveryServerUrl) { UA_Client *client = UA_Client_new(UA_ClientConfig_default); UA_EndpointDescription *endpointArray = NULL; size_t endpointArraySize = 0; UA_StatusCode retval = UA_Client_getEndpoints(client, discoveryServerUrl, &endpointArraySize, &endpointArray); if (retval != UA_STATUSCODE_GOOD) { UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "GetEndpoints failed with %s", UA_StatusCode_name(retval)); UA_Client_delete(client); return NULL; } UA_LOG_DEBUG(logger, UA_LOGCATEGORY_SERVER, "Server has %ld endpoints", endpointArraySize); UA_EndpointDescription *foundEndpoint = NULL; for (size_t i = 0; i < endpointArraySize; i++) { UA_LOG_DEBUG(logger, UA_LOGCATEGORY_SERVER, "\tURL = %.*s, SecurityMode = %s", (int) endpointArray[i].endpointUrl.length, endpointArray[i].endpointUrl.data, endpointArray[i].securityMode == UA_MESSAGESECURITYMODE_NONE ? "None" : endpointArray[i].securityMode == UA_MESSAGESECURITYMODE_SIGN ? "Sign" : endpointArray[i].securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ? "SignAndEncrypt" : "Invalid" ); // find the endpoint with highest supported security mode if ((UA_String_equal(&endpointArray[i].securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI) || UA_String_equal(&endpointArray[i].securityPolicyUri, &UA_SECURITY_POLICY_BASIC128_URI)) && ( foundEndpoint == NULL || foundEndpoint->securityMode < endpointArray[i].securityMode)) foundEndpoint = &endpointArray[i]; } UA_EndpointDescription *returnEndpoint = NULL; if (foundEndpoint != NULL) { returnEndpoint = UA_EndpointDescription_new(); UA_EndpointDescription_copy(foundEndpoint, returnEndpoint); } UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); return returnEndpoint; }
static UA_StatusCode GetEndpoints(UA_Client *client, const UA_String* endpointUrl, size_t* endpointDescriptionsSize, UA_EndpointDescription** endpointDescriptions, const char* filterTransportProfileUri) { UA_GetEndpointsRequest request; UA_GetEndpointsRequest_init(&request); //request.requestHeader.authenticationToken = client->authenticationToken; request.requestHeader.timestamp = UA_DateTime_now(); request.requestHeader.timeoutHint = 10000; request.endpointUrl = *endpointUrl; // assume the endpointurl outlives the service call if (filterTransportProfileUri) { request.profileUrisSize = 1; request.profileUris = (UA_String*)UA_malloc(sizeof(UA_String)); request.profileUris[0] = UA_String_fromChars(filterTransportProfileUri); } UA_GetEndpointsResponse response; UA_GetEndpointsResponse_init(&response); __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]); if (filterTransportProfileUri) { UA_Array_delete(request.profileUris, request.profileUrisSize, &UA_TYPES[UA_TYPES_STRING]); } ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD); *endpointDescriptionsSize = response.endpointsSize; *endpointDescriptions = (UA_EndpointDescription*)UA_Array_new(response.endpointsSize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); for(size_t i=0;i<response.endpointsSize;i++) { UA_EndpointDescription_init(&(*endpointDescriptions)[i]); UA_EndpointDescription_copy(&response.endpoints[i], &(*endpointDescriptions)[i]); } UA_GetEndpointsResponse_deleteMembers(&response); return UA_STATUSCODE_GOOD; }
/* Combination of UA_Client_getEndpointsInternal and getEndpoints */ static void responseGetEndpoints(UA_Client *client, void *userdata, UA_UInt32 requestId, void *response) { UA_EndpointDescription* endpointArray = NULL; size_t endpointArraySize = 0; UA_GetEndpointsResponse* resp; resp = (UA_GetEndpointsResponse*)response; if (resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { client->connectStatus = resp->responseHeader.serviceResult; UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "GetEndpointRequest failed with error code %s", UA_StatusCode_name (client->connectStatus)); UA_GetEndpointsResponse_deleteMembers(resp); return; } endpointArray = resp->endpoints; endpointArraySize = resp->endpointsSize; resp->endpoints = NULL; resp->endpointsSize = 0; UA_Boolean endpointFound = false; UA_Boolean tokenFound = false; UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"); UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/" "Transport/uatcp-uasc-uabinary"); // TODO: compare endpoint information with client->endpointUri for(size_t i = 0; i < endpointArraySize; ++i) { UA_EndpointDescription* endpoint = &endpointArray[i]; /* look out for binary transport endpoints */ /* Note: Siemens returns empty ProfileUrl, we will accept it as binary */ if(endpoint->transportProfileUri.length != 0 && !UA_String_equal (&endpoint->transportProfileUri, &binaryTransport)) continue; /* Look for an endpoint corresponding to the client security policy */ if(!UA_String_equal(&endpoint->securityPolicyUri, &client->channel.securityPolicy->policyUri)) continue; endpointFound = true; /* Look for a user token policy with an anonymous token */ for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) { UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j]; /* Usertokens also have a security policy... */ if(userToken->securityPolicyUri.length > 0 && !UA_String_equal(&userToken->securityPolicyUri, &securityNone)) continue; /* Does the token type match the client configuration? */ if((userToken->tokenType == UA_USERTOKENTYPE_ANONYMOUS && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] && client->config.userIdentityToken.content.decoded.type != NULL) || (userToken->tokenType == UA_USERTOKENTYPE_USERNAME && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) || (userToken->tokenType == UA_USERTOKENTYPE_CERTIFICATE && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) || (userToken->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN && client->config.userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])) continue; /* Endpoint with matching usertokenpolicy found */ tokenFound = true; UA_EndpointDescription_deleteMembers(&client->config.endpoint); UA_EndpointDescription_copy(endpoint, &client->config.endpoint); UA_UserTokenPolicy_deleteMembers(&client->config.userTokenPolicy); UA_UserTokenPolicy_copy(userToken, &client->config.userTokenPolicy); break; } } UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); if(!endpointFound) { UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "No suitable endpoint found"); client->connectStatus = UA_STATUSCODE_BADINTERNALERROR; } else if(!tokenFound) { UA_LOG_ERROR(&client->config.logger, UA_LOGCATEGORY_CLIENT, "No suitable UserTokenPolicy found for the possible endpoints"); client->connectStatus = UA_STATUSCODE_BADINTERNALERROR; } requestSession(client, &requestId); }
void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_CreateSessionResponse *response) { if(channel->securityToken.channelId == 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID; return; } /* Allocate the response */ response->serverEndpoints = (UA_EndpointDescription*) UA_Array_new(server->config.endpoints.count, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); if(!response->serverEndpoints) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } response->serverEndpointsSize = server->config.endpoints.count; /* Copy the server's endpointdescriptions into the response */ for(size_t i = 0; i < server->config.endpoints.count; ++i) response->responseHeader.serviceResult |= UA_EndpointDescription_copy(&server->config.endpoints.endpoints[0].endpointDescription, &response->serverEndpoints[i]); /* Mirror back the endpointUrl */ for(size_t i = 0; i < response->serverEndpointsSize; ++i) { UA_String_deleteMembers(&response->serverEndpoints[i].endpointUrl); UA_String_copy(&request->endpointUrl, &response->serverEndpoints[i].endpointUrl); } UA_Session *newSession; response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession); if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Processing CreateSessionRequest failed"); return; } /* Fill the session with more information */ newSession->maxResponseMessageSize = request->maxResponseMessageSize; newSession->maxRequestMessageSize = channel->connection->localConf.maxMessageSize; response->responseHeader.serviceResult |= UA_ApplicationDescription_copy(&request->clientDescription, &newSession->clientDescription); /* Prepare the response */ response->sessionId = newSession->sessionId; response->revisedSessionTimeout = (UA_Double)newSession->timeout; response->authenticationToken = newSession->authenticationToken; response->responseHeader.serviceResult = UA_String_copy(&request->sessionName, &newSession->sessionName); if(server->config.endpoints.count > 0) response->responseHeader.serviceResult |= UA_ByteString_copy(&server->config.endpoints.endpoints[0].endpointDescription.serverCertificate, &response->serverCertificate); /* Failure -> remove the session */ if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_SessionManager_removeSession(&server->sessionManager, &newSession->authenticationToken); return; } UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Session " UA_PRINTF_GUID_FORMAT " created", UA_PRINTF_GUID_DATA(newSession->sessionId.identifier.guid)); }
void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_CreateSessionResponse *response) { if(channel == NULL) { response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; return; } if(channel->connection == NULL) { response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR; return; } UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Trying to create session"); if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN || channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) { if(!UA_ByteString_equal(&request->clientCertificate, &channel->remoteCertificate)) { response->responseHeader.serviceResult = UA_STATUSCODE_BADCERTIFICATEINVALID; return; } } if(channel->securityToken.channelId == 0) { response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID; return; } if(!UA_ByteString_equal(&channel->securityPolicy->policyUri, &UA_SECURITY_POLICY_NONE_URI) && request->clientNonce.length < 32) { response->responseHeader.serviceResult = UA_STATUSCODE_BADNONCEINVALID; return; } ////////////////////// TODO: Compare application URI with certificate uri (decode certificate) /* Allocate the response */ response->serverEndpoints = (UA_EndpointDescription*) UA_Array_new(server->config.endpointsSize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]); if(!response->serverEndpoints) { response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY; return; } response->serverEndpointsSize = server->config.endpointsSize; /* Copy the server's endpointdescriptions into the response */ for(size_t i = 0; i < server->config.endpointsSize; ++i) response->responseHeader.serviceResult |= UA_EndpointDescription_copy(&server->config.endpoints[0].endpointDescription, &response->serverEndpoints[i]); if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) return; /* Mirror back the endpointUrl */ for(size_t i = 0; i < response->serverEndpointsSize; ++i) { UA_String_deleteMembers(&response->serverEndpoints[i].endpointUrl); UA_String_copy(&request->endpointUrl, &response->serverEndpoints[i].endpointUrl); } UA_Session *newSession; response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession); if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Processing CreateSessionRequest failed"); return; } /* Fill the session with more information */ newSession->maxResponseMessageSize = request->maxResponseMessageSize; newSession->maxRequestMessageSize = channel->connection->localConf.maxMessageSize; response->responseHeader.serviceResult |= UA_ApplicationDescription_copy(&request->clientDescription, &newSession->clientDescription); /* Prepare the response */ response->sessionId = newSession->sessionId; response->revisedSessionTimeout = (UA_Double)newSession->timeout; response->authenticationToken = newSession->authenticationToken; response->responseHeader.serviceResult = UA_String_copy(&request->sessionName, &newSession->sessionName); if(server->config.endpointsSize > 0) response->responseHeader.serviceResult |= UA_ByteString_copy(&channel->securityPolicy->localCertificate, &response->serverCertificate); /* Create a signed nonce */ response->responseHeader.serviceResult = nonceAndSignCreateSessionResponse(server, channel, newSession, request, response); /* Failure -> remove the session */ if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) { UA_SessionManager_removeSession(&server->sessionManager, &newSession->authenticationToken); return; } UA_LOG_DEBUG_CHANNEL(server->config.logger, channel, "Session " UA_PRINTF_GUID_FORMAT " created", UA_PRINTF_GUID_DATA(newSession->sessionId.identifier.guid)); }