Files
Maison/RdpBroker/PROTOCOL.md
2026-02-10 12:12:11 +01:00

337 lines
8.6 KiB
Markdown

# 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:**
```json
{
"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:**
```json
{
"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:**
```json
{
"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:**
```json
{
"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
```c
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
```c
int auth_result = authenticate_user(username, password,
config->samba_server,
config->samba_port,
config->base_dn);
```
### 4. Get User's Authorized Targets
```c
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:**
```yaml
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
```c
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
```c
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
```c
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
1. **Always validate target selection** - User must be authorized for selected target
2. **Close on protocol errors** - Invalid messages should immediately close connection
3. **Timeout authentication** - Implement timeout for AUTH phase (e.g., 30 seconds)
4. **Rate limiting** - Prevent brute force attacks on authentication
5. **Logging** - Log all authentication attempts and target selections
6. **TLS/SSL** - Consider wrapping connection in TLS for production
## Testing
### Test Authentication Success
```bash
(echo -e "AUTH\nuser@example.com\nPassword123\n"; sleep 1) | nc rdpbroker 3389
```
Expected response:
```json
{"type":"auth_success","targets":[...]}
```
### Test Authentication Failure
```bash
(echo -e "AUTH\nuser@example.com\nWrongPassword\n"; sleep 1) | nc rdpbroker 3389
```
Expected response:
```json
{"type":"auth_failed","message":"Invalid credentials"}
```
### Test Target Selection
```bash
(echo -e "AUTH\nuser@example.com\nPassword123\n"; sleep 1; echo -e "SELECT\nWindows Server 2022\n"; sleep 1) | nc rdpbroker 3389
```
Expected response:
```json
{"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:
1. Accept the new text-based protocol on initial connection
2. Parse AUTH and SELECT commands
3. Return JSON responses instead of RDP login screens
4. 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