Newer Older
288 lines | 7.473kb
Bogdan Timofte authored 2 weeks ago
1
#!/usr/bin/env bash
2
set -euo pipefail
3

            
4
real_ssh="/usr/bin/ssh"
5
ssh_config="$HOME/.ssh/config"
6
remote_agent="/run/user/0/gnupg/S.gpg-agent.ssh"
7

            
8
# Access model, May 2026
9
# ----------------------
10
#
11
# Cheia fizica este montata pe is-jumper. Wrapper-ul local nu mai face bridge
12
# de agent in /tmp; in schimb ruleaza clientul SSH activ pe is-jumper:
13
#
14
#     local ssh wrapper
15
#       -> is-jumper (192.168.2.100, acces local cu id_ed25519)
16
#       -> J1/J2/j1/j2 (autentificare cu agentul fizic de pe is-jumper)
17
#       -> ssh final-host
18
#
19
# Custom jump flags (stripped by wrapper, not passed to real ssh):
20
#   -J1  use J1 via VPN (default for configured hosts)
21
#   -J2  use J2 via VPN
22
#   -j1  use j1 via public DNS (urgente, fara ruta VPN)
23
#   -j2  use j2 via public DNS (urgente, fara ruta VPN)
24
#
25
# Hosturi arbitrare (fara config SSH): wrapper-ul le ruteza prin jump doar daca
26
# unul dintre flagurile de mai sus este prezent explicit.
27

            
28
target_user=""
29
target_host=""
30
target_port=""
31
target_auth=""
32
found_target=0
33
cmd_args=()
34
ssh_config_args=()
35
jump_alias="j1"
36
custom_jump_set=0
37
host_configured=1
38
target_is_jump=0
39
want_subsystem=0
40
user_option=""
41
port_option=""
42

            
43
has_explicit_config() {
44
    local arg
45

            
46
    for arg in "$@"; do
47
        case "$arg" in
48
            -F|-F*)
49
                return 0
50
                ;;
51
        esac
52
    done
53

            
54
    return 1
55
}
56

            
57
quote_cmd() {
58
    local out="" q part
59

            
60
    for part in "$@"; do
61
        printf -v q "%q" "$part"
62
        out+="$q "
63
    done
64

            
65
    printf "%s" "$out"
66
}
67

            
68
resolve_ssh_config() {
69
    local target=$1
70
    local line
71

            
72
    target_user=""
73
    target_host=""
74
    target_port=""
75
    target_auth=""
76

            
77
    while IFS= read -r line; do
78
        case "$line" in
79
            user\ *)     target_user=${line#user } ;;
80
            hostname\ *) target_host=${line#hostname } ;;
81
            port\ *)     target_port=${line#port } ;;
82
            setenv\ *NG_SSH_AUTH=password-interactive*) target_auth="password_interactive" ;;
83
        esac
84
    done < <("$real_ssh" ${ssh_config_args[@]+"${ssh_config_args[@]}"} -G "$target" 2>/dev/null)
85

            
86
    [[ -n "$target_user" && -n "$target_host" && -n "$target_port" ]]
87
}
88

            
89
run_real_ssh() {
90
    exec "$real_ssh" ${ssh_config_args[@]+"${ssh_config_args[@]}"} "$@"
91
}
92

            
93
resolve_target_from_config() {
94
    local target=$1
95
    local default_user=${USER:-${LOGNAME:-}}
96
    local user_override=""
97

            
98
    case "$target" in
99
        *@*)
100
            user_override=${target%@*}
101
            target=${target#*@}
102
            ;;
103
    esac
104

            
105
    case "$target" in
106
        is-jumper|192.168.2.100)
107
            return 1
108
            ;;
109
        J1|J2|j1|j2)
110
            target_is_jump=1
111
            ;;
112
    esac
113

            
114
    resolve_ssh_config "$target" || return 1
115

            
116
    if [[ -n "$user_override" ]]; then
117
        target_user=$user_override
118
    fi
119
    if [[ -n "$user_option" ]]; then
120
        target_user=$user_option
121
    fi
122
    if [[ -n "$port_option" ]]; then
123
        target_port=$port_option
124
    fi
125

            
126
    # Unconfigured host (ssh -G returns defaults): bypass unless a custom jump
127
    # was requested explicitly.
128
    if [[ "$target_is_jump" -eq 0 && "$target_host" == "$target" && "$target_port" == "22" && "$target_user" == "$default_user" ]]; then
129
        [[ $custom_jump_set -eq 0 ]] && return 1
130
        host_configured=0
131
    fi
132

            
133
    [[ -n "$target_user" && -n "$target_host" && -n "$target_port" ]]
134
}
135

            
136
resolve_jump() {
137
    local saved_user saved_host saved_port saved_auth
138

            
139
    saved_user=$target_user
140
    saved_host=$target_host
141
    saved_port=$target_port
142
    saved_auth=$target_auth
143

            
144
    resolve_ssh_config "$jump_alias" || {
145
        printf "ssh-wrapper: cannot resolve jump alias %s\n" "$jump_alias" >&2
146
        exit 255
147
    }
148

            
149
    jump_user=$target_user
150
    jump_host=$target_host
151
    jump_port=$target_port
152

            
153
    target_user=$saved_user
154
    target_host=$saved_host
155
    target_port=$saved_port
156
    target_auth=$saved_auth
157
}
158

            
159
# Pre-process: extract custom jump flags and strip them from args.
160
filtered_args=()
161
for arg in "$@"; do
162
    case "$arg" in
163
        -J1) jump_alias="j1"; custom_jump_set=1 ;;
164
        -J2) jump_alias="j2"; custom_jump_set=1 ;;
165
        -j1) jump_alias="j1"; custom_jump_set=1 ;;
166
        -j2) jump_alias="j2"; custom_jump_set=1 ;;
167
        *) filtered_args+=("$arg") ;;
168
    esac
169
done
170
set -- "${filtered_args[@]+"${filtered_args[@]}"}"
171

            
172
if [[ -f "$ssh_config" ]] && ! has_explicit_config "$@"; then
173
    ssh_config_args=(-F "$ssh_config")
174
fi
175

            
176
skip_next=0
177
capture_user=0
178
capture_port=0
179
after_double_dash=0
180

            
181
for arg in "$@"; do
182
    if [[ $found_target -eq 1 ]]; then
183
        cmd_args+=("$arg")
184
        continue
185
    fi
186

            
187
    if [[ $capture_user -eq 1 ]]; then
188
        user_option=$arg
189
        capture_user=0
190
        continue
191
    fi
192

            
193
    if [[ $capture_port -eq 1 ]]; then
194
        port_option=$arg
195
        capture_port=0
196
        continue
197
    fi
198

            
199
    if [[ $skip_next -eq 1 ]]; then
200
        skip_next=0
201
        continue
202
    fi
203

            
204
    case "$arg" in
205
        -G|-Q|-V|-h|--help)
206
            run_real_ssh "$@"
207
            ;;
208
        --)
209
            after_double_dash=1
210
            continue
211
            ;;
212
    esac
213

            
214
    if [[ $after_double_dash -eq 0 ]]; then
215
        case "$arg" in
216
            -s)
217
                want_subsystem=1
218
                continue
219
                ;;
220
            -l)
221
                capture_user=1
222
                continue
223
                ;;
224
            -l*)
225
                user_option=${arg#-l}
226
                continue
227
                ;;
228
            -p)
229
                capture_port=1
230
                continue
231
                ;;
232
            -p*)
233
                port_option=${arg#-p}
234
                continue
235
                ;;
236
            -b|-c|-D|-E|-e|-F|-I|-i|-J|-L|-m|-O|-o|-Q|-R|-S|-W|-w)
237
                skip_next=1
238
                continue
239
                ;;
240
            -b*|-c*|-D*|-E*|-e*|-F*|-I*|-i*|-J*|-L*|-m*|-O*|-o*|-Q*|-R*|-S*|-W*|-w*)
241
                continue
242
                ;;
243
            -*)
244
                continue
245
                ;;
246
        esac
247
    fi
248

            
249
    if ! resolve_target_from_config "$arg"; then
250
        run_real_ssh "$@"
251
    fi
252

            
253
    found_target=1
254
done
255

            
256
if [[ $found_target -eq 0 ]]; then
257
    run_real_ssh "$@"
258
fi
259

            
260
tty_flag="-tt"
261
if [[ ${#cmd_args[@]} -gt 0 || $want_subsystem -eq 1 ]]; then
262
    tty_flag="-T"
263
fi
264

            
265
if [[ $target_is_jump -eq 1 ]]; then
266
    jump_cmd=(ssh "$tty_flag" -A -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -p "$target_port" "$target_user@$target_host")
267
    jump_cmd+=(${cmd_args[@]+"${cmd_args[@]}"})
268
else
269
    resolve_jump
270

            
271
    final_cmd=(ssh "$tty_flag" -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -o ProxyJump=none -o ProxyCommand=none)
272
    if [[ "$target_auth" == "password_interactive" ]]; then
273
        final_cmd+=( -o BatchMode=no -o PreferredAuthentications=keyboard-interactive,password -o PubkeyAuthentication=no )
274
    elif [[ $host_configured -eq 1 ]]; then
275
        final_cmd+=( -o BatchMode=yes )
276
    fi
277
    if [[ $want_subsystem -eq 1 ]]; then
278
        final_cmd+=( -s )
279
    fi
280
    final_cmd+=( -p "$target_port" "$target_user@$target_host" )
281
    final_cmd+=(${cmd_args[@]+"${cmd_args[@]}"})
282

            
283
    jump_cmd=(ssh "$tty_flag" -A -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -p "$jump_port" "$jump_user@$jump_host" "$(quote_cmd "${final_cmd[@]}")")
284
fi
285

            
286
is_jumper_cmd="SSH_AUTH_SOCK=$remote_agent exec $(quote_cmd "${jump_cmd[@]}")"
287

            
288
exec "$real_ssh" ${ssh_config_args[@]+"${ssh_config_args[@]}"} "$tty_flag" -o BatchMode=yes -o ConnectTimeout=10 is-jumper "$is_jumper_cmd"