8.6 KiB
RdpBroker Protocol Specification
Overview
This document describes the protocol between web-gateway and RdpBroker for user authentication and target management.
Connection Flow
Web-Gateway RdpBroker Samba AD / Target RDP Servers
| | |
|--AUTH\n{user}\n{pass}\n----->| |
| |---LDAP Auth----------------->|
| |<----Auth Result--------------|
| | |
|<---{type:targets,targets:[]}| |
| OR | |
|<---{type:auth_failed}--------| |
| | |
|--SELECT\n{target_name}\n---->| |
| |---Connect to Target--------->|
|<---{type:rdp_ready}----------|<-----------------------------|
| | |
|<====== RDP Binary Data ======|<===== RDP Session ==========|
Protocol Messages
Phase 1: Authentication
Request Format (Web-Gateway → RdpBroker)
AUTH\n
username\n
password\n
Example:
AUTH
user@example.com
SecurePassword123
Success Response (RdpBroker → Web-Gateway)
JSON Format:
{
"type": "auth_success",
"targets": [
{
"name": "Windows Server 2022",
"host": "ws2022.example.com",
"port": 3389,
"description": "Production Windows Server"
},
{
"name": "Development Server",
"host": "dev.example.com",
"port": 3389,
"description": "Development environment"
}
]
}
Notes:
- The message must end with
\n\n(double newline) to signal end of JSON message - Targets list is personalized based on user permissions/groups in Samba AD
- Empty array means user is authenticated but has no authorized targets
Failure Response (RdpBroker → Web-Gateway)
JSON Format:
{
"type": "auth_failed",
"message": "Invalid credentials"
}
Followed by connection close.
Possible error messages:
- "Invalid credentials"
- "User account disabled"
- "LDAP connection failed"
- "User not authorized for any targets"
Phase 2: Target Selection
Request Format (Web-Gateway → RdpBroker)
SELECT\n
target_name\n
Example:
SELECT
Windows Server 2022
Notes:
- Target name must match exactly one of the names from the targets list
- Connection should be rejected if target name is invalid or not in user's authorized list
Success Response (RdpBroker → Web-Gateway)
JSON Format:
{
"type": "rdp_ready"
}
Followed by \n\n, then RDP binary data stream begins.
After this message, the connection transitions to raw RDP protocol forwarding mode.
Failure Response (RdpBroker → Web-Gateway)
JSON Format:
{
"type": "error",
"message": "Target not available"
}
Followed by connection close.
Possible error messages:
- "Target not found"
- "Target not authorized for user"
- "Failed to connect to target server"
- "Target server unreachable"
Phase 3: RDP Session
After rdp_ready message, all subsequent data is raw RDP protocol:
- Web-Gateway forwards mouse/keyboard events as RDP protocol data
- RdpBroker forwards screen updates as RDP protocol data
- Connection is bidirectional binary stream
Implementation Guidelines for RdpBroker
1. Accept Connection
Listen on port 3389 (configurable via RDP_LISTEN_PORT)
2. Read Authentication Message
char buffer[4096];
int bytes = read(client_fd, buffer, sizeof(buffer));
// Parse "AUTH\n{username}\n{password}\n"
char *lines[3];
int line_count = 0;
char *token = strtok(buffer, "\n");
while (token != NULL && line_count < 3) {
lines[line_count++] = token;
token = strtok(NULL, "\n");
}
if (strcmp(lines[0], "AUTH") != 0) {
send_error(client_fd, "Invalid protocol");
close(client_fd);
return;
}
char *username = lines[1];
char *password = lines[2];
3. Authenticate with Samba AD
int auth_result = authenticate_user(username, password,
config->samba_server,
config->samba_port,
config->base_dn);
4. Get User's Authorized Targets
rdp_target_t *user_targets[MAX_TARGETS];
int target_count = get_user_targets(username, config, user_targets);
Recommended approach:
- Query user's groups from LDAP
- Filter targets based on group membership or user attributes
- Return only targets the user is authorized to access
Example YAML configuration:
targets:
- name: "Windows Server 2022"
host: "ws2022.example.com"
port: 3389
description: "Production Windows Server"
authorized_groups:
- "Domain Admins"
- "Server Operators"
- name: "Development Server"
host: "dev.example.com"
port: 3389
description: "Development environment"
authorized_groups:
- "Developers"
- "Domain Admins"
5. Send Targets List
char json_response[8192];
snprintf(json_response, sizeof(json_response),
"{\"type\":\"auth_success\",\"targets\":[");
for (int i = 0; i < target_count; i++) {
char target_json[512];
snprintf(target_json, sizeof(target_json),
"%s{\"name\":\"%s\",\"host\":\"%s\",\"port\":%d,\"description\":\"%s\"}",
(i > 0 ? "," : ""),
user_targets[i]->name,
user_targets[i]->host,
user_targets[i]->port,
user_targets[i]->description);
strcat(json_response, target_json);
}
strcat(json_response, "]}\n\n");
write(client_fd, json_response, strlen(json_response));
6. Read Target Selection
bytes = read(client_fd, buffer, sizeof(buffer));
// Parse "SELECT\n{target_name}\n"
if (strncmp(buffer, "SELECT\n", 7) != 0) {
send_error(client_fd, "Invalid protocol");
close(client_fd);
return;
}
char *target_name = buffer + 7;
char *newline = strchr(target_name, '\n');
if (newline) *newline = '\0';
// Verify target is in user's authorized list
rdp_target_t *selected_target = find_target_in_list(target_name,
user_targets,
target_count);
if (!selected_target) {
send_error(client_fd, "Target not authorized");
close(client_fd);
return;
}
7. Connect to Target and Start Forwarding
int target_fd = connect_to_rdp_target(selected_target->host,
selected_target->port);
// Send ready message
char *ready_msg = "{\"type\":\"rdp_ready\"}\n\n";
write(client_fd, ready_msg, strlen(ready_msg));
// Start bidirectional forwarding
forward_rdp_connection(client_fd, target_fd);
Security Considerations
- Always validate target selection - User must be authorized for selected target
- Close on protocol errors - Invalid messages should immediately close connection
- Timeout authentication - Implement timeout for AUTH phase (e.g., 30 seconds)
- Rate limiting - Prevent brute force attacks on authentication
- Logging - Log all authentication attempts and target selections
- TLS/SSL - Consider wrapping connection in TLS for production
Testing
Test Authentication Success
(echo -e "AUTH\nuser@example.com\nPassword123\n"; sleep 1) | nc rdpbroker 3389
Expected response:
{"type":"auth_success","targets":[...]}
Test Authentication Failure
(echo -e "AUTH\nuser@example.com\nWrongPassword\n"; sleep 1) | nc rdpbroker 3389
Expected response:
{"type":"auth_failed","message":"Invalid credentials"}
Test Target Selection
(echo -e "AUTH\nuser@example.com\nPassword123\n"; sleep 1; echo -e "SELECT\nWindows Server 2022\n"; sleep 1) | nc rdpbroker 3389
Expected response:
{"type":"auth_success","targets":[...]}
{"type":"rdp_ready"}
[RDP binary data follows]
Migration Notes
Existing RdpBroker implementations that present login/menu screens via RDP protocol will need to be refactored to:
- Accept the new text-based protocol on initial connection
- Parse AUTH and SELECT commands
- Return JSON responses instead of RDP login screens
- Only start RDP forwarding after receiving SELECT command
The advantage is that authentication and target selection now happen via structured protocol before RDP session starts, allowing:
- Better error handling in web UI
- User-specific target lists
- Cleaner separation of concerns
- Easier debugging and monitoring