-
Notifications
You must be signed in to change notification settings - Fork 21
/
vpn.sh
executable file
·2772 lines (2266 loc) · 79.1 KB
/
vpn.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
#
# Rui Ribeiro
#
# VPN client chroot'ed setup/wrapper for Debian/Ubuntu/RedHat/CentOS/Fedora/Arch/SUSE/Gentoo/Slackware/Void/Deepin/Kwort/Pisi/KaOS/Clear/NuTyx hosts
#
# Checkpoint R80.10 and up
#
# Please fill VPN and VPNIP before using this script.
# SPLIT might or not have to be filled, depending on your needs
# and Checkpoint VPN given routes.
#
# if /opt/etc/vpn.conf is present the above script settings will be
# ignored. vpn.conf is created upon first installation.
#
# first time run it as ./vpn.sh -i --vpn=YOUR.VPN.SERVER
# Accept localhost certificate visiting https://localhost:14186/id if not Firefox
# Then open VPN URL to login/start the VPN
#
# vpn.sh selfupdate
# might update this script if new version+Internet connectivity available
#
# non-chroot version not written intentionally.
# SNX/CShell behave on odd ways;
# the chroot is built to counter some of those behaviours
#
# CShell CheckPoint Java agent needs Java *and* X11 desktop rights
# binary SNX VPN client needs 32-bits environment
#
# tested with chroot both with Debian Bullseye 11/Bookworm 12 (32 bits) and
# 64 bits Linux hosts.
#
# see list and instructions at https://github.com/ruyrybeyro/chrootvpn/
#
# This script uses TABs for output/files.
# BEWARE of cut&paste or code beautifiers, it will break code.
# script/deploy version, make the same as deploy
VERSION="v1.96"
# default configuration file
# created first time upon successful setup/run
# so vpn.sh can be successfuly replaced by new versions
# or reinstalled from scratch
CONFFILE="/opt/etc/vpn.conf"
# if vpn.conf present, source VPN, VPNIP, SPLIT and SSLVPN from it
[[ -f "${CONFFILE}" ]] && . "${CONFFILE}"
# Sane defaults:
# Checkpoint VPN address
# selfupdate brings them from the older version
# Fill VPN *and* VPNIP *before* using the script
# if filling in keep the format
# values used first time installing,
# otherwise /opt/etc/vpn.conf overrides them
[[ -z "$VPN" ]] && VPN=""
[[ -z "$VPNIP" ]] && VPNIP=""
# default chroot location (700 MB needed - 1.5GB while installing)
[[ -z "$CHROOT" ]] && CHROOT="/opt/chroot"
# split VPN routing table if deleting VPN gateway is not enough
# selfupdate brings it from the older version
# if empty script will delete VPN gateway
# if filling in keep the format
# value used first time installing,
# otherwise /opt/etc/vpn.conf overrides it
[[ -z "$SPLIT" ]] && SPLIT=""
# we test / and sslvnp SSL VPN portal PATHs.
# Change here for a custom PATH
[[ -z "$SSLVPN" ]] && SSLVPN="sslvpn"
# used during initial chroot setup
# for chroot shell correct time
# if TZ is empty
# set TZ before first time creating chroot
[[ -z "${TZ}" ]] && TZ='Europe/Lisbon'
# OS to deploy inside 32-bit chroot
# minimal Debian
VARIANT="minbase"
#RELEASE="bullseye" # Debian 11
RELEASE="bookworm" # Debian 12
DEBIANREPO="http://deb.debian.org/debian/" # fastly repo
# github repository for selfupdate command
# https://github.com/ruyrybeyro/chrootvpn
GITHUB_REPO="ruyrybeyro/chrootvpn"
# needed by SLES and Slackware
# version of debootstrap taken from Debian pool repository
# 1.0.128 has bullseye and bookworm rules files
#
#
# http://deb.debian.org/debian/pool/main/d/debootstrap/debootstrap_1.0.128+nmu2_all.deb
# http://deb.debian.org/debian/pool/main/d/debootstrap/debootstrap_1.0.128+nmu2.tar.gz
#
VER_BOOTSTRAP="1.0.128"
DEB_BOOTSTRAP="${DEBIANREPO}pool/main/d/debootstrap/debootstrap_${VER_BOOTSTRAP}+nmu2_all.deb"
DEB_FILE=$(basename ${DEB_BOOTSTRAP})
SRC_BOOTSTRAP="${DEBIANREPO}pool/main/d/debootstrap/debootstrap_${VER_BOOTSTRAP}+nmu2.tar.gz"
# URL for testing if split or full VPN
URL_VPN_TEST="https://www.debian.org"
# CShell writes on the X11 display
[[ -z "${DISPLAY}" ]] && export DISPLAY=":0.0"
# dont bother with locales
# all on plain English
export LC_ALL=C LANG=C
# save local current working directory
LOCALCWD="$(pwd)"
# script full PATH
SCRIPT=$(realpath "${BASH_SOURCE[0]}")
# script name
SCRIPTNAME=$(basename "${SCRIPT}")
# preserves program passed arguments $@ into a BASH array
args=("$@")
# VPN interface created by SNX
TUNSNX="tunsnx"
# xdg autostart X11 file
XDGAUTO="/etc/xdg/autostart/cshell.desktop"
# script PATH upon successful setup
INSTALLSCRIPT="/usr/local/bin/${SCRIPTNAME}"
# Debian/RH script PATH
PKGSCRIPT="/usr/bin/vpn.sh"
# cshell user
CSHELL_USER="cshell"
CSHELL_UID="9000"
CSHELL_GROUP="${CSHELL_USER}"
CSHELL_GID="9000"
CSHELL_HOME="/home/${CSHELL_USER}"
# "booleans"
true=0
false=1
# PATH for being called outside the command line (from xdg)
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/run/current-system/sw/bin:/run/current-system/sw/sbin:${PATH}"
# if true, cwd cshell_install.sh and/or snx_install.sh will be used
# if present
LOCALINSTALL=false
# can be changed for yum
DNF="dnf"
# curl options
CURL_OPT="-k --fail --silent"
#
# user interface handling
#
# -h|--help
#
do_help()
{
# non documented options
# vpn.sh --osver showing OS version
cat <<-EOF1
VPN client setup for Debian/Ubuntu
Checkpoint R80.10+ ${VERSION}
${SCRIPTNAME} [-l][-f FILE|--file=FILE][-c DIR|--chroot=DIR][--proxy=proxy_string][--vpn=FQDN] -i|--install
${SCRIPTNAME} [-f FILE|--file=FILE][-o FILE|--output=FILE][-c DIR|--chroot=DIR] start|stop|restart|status
${SCRIPTNAME} [-f FILE|--file=FILE][-c DIR|--chroot=DIR] [uninstall|rmchroot]
${SCRIPTNAME} [-f FILE|--file=FILE][-o FILE|--output=FILE] disconnect|split|selfupdate|fixdns
${SCRIPTNAME} -h|--help
${SCRIPTNAME} -v|--version
-i|--install install mode - creates chroot
-c|--chroot changes default chroot ${CHROOT} directory
-h|--help shows this help
-v|--version script version
-f|--file alternate conf file. Default /opt/etc/vpn.conf
-l gets snx_install.sh and/or cshell_install.sh from cwd directory
the files wont be loaded from the remote CheckPoint
--vpn selects the VPN DNS full name at install time
--proxy proxy to use in apt inside chroot 'http://user:pass@IP'
--portalurl custom VPN portal URL prefix (usually sslvpn or /) ;
use it as --portalurl=STRING together with --install
-o|--output redirects ALL output for FILE
-s|--silent special case of output, no arguments
start starts CShell daemon
stop stops CShell daemon
restart restarts CShell daemon
status checks if CShell daemon is running
disconnect disconnects VPN/SNX session from the command line
split split tunnel VPN mode - use only after session is up
uninstall deletes chroot and host file(s)
rmchroot deletes chroot
selfupdate self-updates this script if new version available
fixdns tries to fix resolv.conf
policy tries to install Firefox policy
For debugging/maintenance:
${SCRIPTNAME} -d|--debug
${SCRIPTNAME} [-c DIR|--chroot=DIR] shell|upgrade
-d|--debug bash debug mode on
shell bash shell inside chroot
upgrade OS upgrade inside chroot
sudoers installs in /etc/sudoers sudo permission for the user
log shows CShell Jetty logs
tailog follows/tail CShell Jetty logs
URL for accepting CShell localhost certificate
https://localhost:14186/id
EOF1
# exits after help
exit 0
}
# complains to STDERR and exit with error
die()
{
# calling function name: message
echo "${FUNCNAME[2]}->${FUNCNAME[1]}: $*" >&2
exit 2
}
# DNS lookup: getent is installed by default
vpnlookup()
{
# resolves IPv4 IP address of DNS name $VPN
VPNIP=$(getent ahostsv4 "${VPN}" | awk 'NR==1 { print $1 } ' )
[[ -z "${VPNIP}" ]] && die "could not resolve ${VPN} DNS name"
}
# tests if user in a group
#
# $1 = group
# $2 = user
#
# $2 is optional
#
ingroup()
{
[[ " `id -Gn ${2-}` " == *" $1 "* ]];
}
# optional arguments handling
needs_arg()
{
[[ -z "${OPTARG}" ]] && die "No arg for --$OPT option"
}
# Redirect Output
#
# -o|--output FILE
# -s|--silent called with /dev/null
#
# $1 : log file to use
#
doOutput()
{
LOG_FILE="$1"
# Close standard output file descriptor
exec 1<&-
# Close standard error file descriptor
exec 2<&-
# Open standard output as LOG_FILE for read and write.
exec 1<> "${LOG_FILE}"
# Redirect standard error to standard output
exec 2>&1
}
# write /etc/sudoers
# giving sudo permission for script
doSudoers()
{
if [[ -e /etc/sudoers ]]
then
if [[ -z "${SUDO_USER}" ]]
then
die "running script as root, sudoers no written"
else
if [[ -e "/usr/bin/vpn.sh" ]]
then
echo "${SUDO_USER} ALL=(ALL:ALL) NOPASSWD: /usr/bin/vpn.sh" >> /etc/sudoers >&2
fi
if [[ "${INSTALLSCRIPT}" != "/usr/bin/vpn.sh" ]]
then
echo "${SUDO_USER} ALL=(ALL:ALL) NOPASSWD: ${INSTALLSCRIPT}" >> /etc/sudoers >&2
fi
fi
else
die "no /etc/sudoers. Install sudo package"
fi
}
# arguments - script getopts options handling
doGetOpts()
{
# install status flag
install=false
# process command line options
while getopts dic:-:o:shvf:l OPT
do
# long option -- , - handling
# reformulate OPT and OPTARG
# arguments are
# OPT equals name of long options
# = separator/delimiter
# OPTARG argument
# as in --vpn=myvpn.myorg.com
# OPT=vpn
# OPTARG=myvpn.myorg.com
#
if [[ "${OPT}" = "-" ]]
then
OPT=${OPTARG%%=*} # extract long option name
OPTARG=${OPTARG#"$OPT"} # extract long option argument (may be empty)
OPTARG=${OPTARG#=} # if long option argument, remove assigning `=`
fi
# handle normal or long option
case "${OPT}" in
i | install ) install=true ;; # install chroot
c | chroot ) needs_arg # change location of change on runtime
CHROOT="${OPTARG}" ;;
vpn ) needs_arg # use other VPN on runtime
VPN="${OPTARG}"
vpnlookup ;;
proxy ) needs_arg # APT proxy inside chroot
CHROOTPROXY="${OPTARG}" ;;
portalurl ) needs_arg # VPN portal URL prefix
SSLVPN="${OPTARG}" ;;
v | version ) echo "${VERSION}" # script version
exit 0 ;;
osver) awk -F"=" '/^PRETTY_NAME/ { gsub("\"","");print $2 } ' /etc/os-release
exit 0 ;;
o | output ) needs_arg
doOutput "${OPTARG}" ;;
s | silent ) doOutput "/dev/null" ;;
d | debug ) set -x ;; # bash debug on
h | help ) do_help ;; # show help
f | file ) needs_arg # alternate configuration file
# support for multiple clients/VPNs
CONFFILE="${OPTARG}"
[[ -e $CONFFILE ]] || die "no configuration file $CONFFILE"
# shellcheck disable=SC1090
. "${CONFFILE}" ;;
l) LOCALINSTALL=true ;; # if cwd snx/cshell_install.sh, uses it
sudoers) doSudoers
exit 0 ;;
??* ) die "Illegal option --${OPT}" ;; # bad long option
? ) exit 2;; # bad short option (reported by getopts)
esac
done
}
# finds which distribution we are dealing with
getDistro()
{
local ID
local ID_LIKE
local DISTRIB
local SystemName
local i
# init distro flags
DEB=0
RH=0
ARCH=0
SUSE=0
GENTOO=0
SLACKWARE=0
VOID=0
DEEPIN=0
KWORT=0
PISI=0
CLEAR=0
ALPINE=0
NUTYX=0
NIXOS=0
MARINER=0
# installing dpkg damages Solus, commented out
#SOLUS=0
# init variables for later use
# $ID
[[ -f "/etc/os-release" ]] && ID="$(awk -F= ' /^ID=/ { gsub("\"", ""); print $2 } ' /etc/os-release)"
[[ -z "${ID}" ]] && ID="none"
# $ID_LIKE
[[ -f "/etc/os-release" ]] && ID_LIKE="$(awk -F= ' /^ID_LIKE=/ { gsub("\"", ""); print $2 } ' /etc/os-release)"
[[ -z "${ID_LIKE}" ]] && ID_LIKE="none"
# $DISTRIB
[[ -f "/etc/os-release" ]] && DISTRIB="$(awk -F= ' /^DISTRIB/ { gsub("\"", ""); print $2 } ' /etc/os-release)"
[[ -z "${DISTRIB}" ]] && DISTRIB="none"
# $SystemName
[[ -f "/etc/os-version" ]] && SystemName="$(awk -F= '/SystemName=/ { gsub("\"", ""); print $2 } ' /etc/os-version)"
[[ -z "${SystemName}" ]] && SystemName="none"
# start checking for distribution
case "${ID}" in
debian) DEB=1 ;; # OB2D/others
openEuler) RH=1 ;;
Euler) RH=1 ;;
kaos) ARCH=1 ;;
kwort) KWORT=1 ;;
clear-linux-os) CLEAR=1 ;;
nutyx) NUTYX=1 ;;
nixos) NIXOS=1 ;;
mariner) RH=1
MARINER=1 ;;
esac
# Dealing with a lot of distributions and derivatives
# So lots of apparent "redundant code" for dealing with differences
# and "particularities"
# [[ "${ID}" == "crux" ]] && CRUX=1
if [[ -f "/etc/debian_version" ]]
then
DEB=1 # is Debian family
# nice to have, but buggy, only warning and not aborting.
# systemd-detect-virt -r an alternative
ischroot && echo "Inside a chroot?" >&2
fi
# Debian / DEEPIN handled slightly differently
# Deepin
# forces DEB=1 because as of Deepin 23, /etc/debian_version no longer there
[[ "${SystemName}" == Deepin ]] && DEEPIN=1 && DEB=1
# RedHat
[[ -f "/etc/redhat-release" ]] && RH=1 # is RedHat family
[[ -f "/etc/openEuler-release" ]] && RH=1
# Arch
[[ -f "/etc/arch-release" ]] && ARCH=1 # is Arch family
[[ "${ID_LIKE}" == "arch" ]] && ARCH=1 # Peux
# SUSE
[[ -f "/etc/SUSE-brand" ]] && SUSE=1 # is SUSE family
[[ "$ID_LIKE" = *"suse"* ]] && SUSE=1 # OpenSUSE and SUSE
# Gentoo
[[ -f "/etc/gentoo-release" ]] && GENTOO=1 # is GENTOO family
[[ -f "/etc/redcore-release" ]] && GENTOO=1 # is GENTOO family
# Slackware
[[ -f "/etc/slackware-version" ]] && SLACKWARE=1 # is Slackware
# Void
[[ "${DISTRIB}" == "void" ]] && VOID=1 # Void Linux
# Solus
#[[ -f "/etc/solus-release" ]] && SOLUS=1 # is Solus family
# Pisi
[[ -f "/etc/pisilinux-release" ]] && PISI=1 # is PISI
# Alpine
[[ -f "/etc/alpine-release" ]] && ALPINE=1 # is Alpine
# NixOS
[[ -f "/etc/NIXOS" ]] && NIXOS=1 # is NixOS
# if installing or showing status
if [[ "${install}" -eq true ]] || [[ "$1" == "status" ]]
then
# shows some variables from system files
# if ID, ID_LIKE, DISTRIB, SystemName
# are not "none"
# print it = their contents
#
for i in ID ID_LIKE DISTRIB SystemName
do
[[ "${!i}" != "none" ]] && echo "${i}=${!i}"
done
# shows which distribution variable(s) is true
for i in DEB DEEPIN RH ARCH SUSE GENTOO SLACKWARE VOID KWORT PISI CLEAR ALPINE NUTYX NIXOS
do
[[ "${!i}" -eq 1 ]] && echo "${i}=true"
done
if [[ "$1" == "status" ]]
then
# displays the contents of distribution /etc release files
for i in "os-release" "os-version" "debian_version" "redhat-release" "openEuler-release" "arch-release" "SUSE-brand" "gentoo-release" "redcore-release" "slackware-version" "pisilinux-release" "alpine-release"
do
[[ -f "/etc/$i" ]] && echo "cat /etc/$i" && cat "/etc/$i" && echo
done
fi
fi
# if none of distribution families above, abort
[[ "${DEB}" -eq 0 ]] && [[ "${RH}" -eq 0 ]] && [[ "${ARCH}" -eq 0 ]] && [[ "${SUSE}" -eq 0 ]] && [[ "${GENTOO}" -eq 0 ]] && [[ "${SLACKWARE}" -eq 0 ]] && [[ "${VOID}" -eq 0 ]] && [[ "${KWORT}" -eq 0 ]] && [[ "${PISI}" -eq 0 ]] && [[ "${CLEAR}" -eq 0 ]] && [[ "${ALPINE}" -eq 0 ]] && [[ "${NUTYX}" -eq 0 ]] && [[ "${NIXOS}" -eq 0 ]] && die "Only Debian, RedHat, ArchLinux, SUSE, Gentoo, Slackware, Void, Deepin, Kwort, Pisi, KaOS, NuTyx, Clear, NixOS and CBL-Mariner Linux family distributions supported"
}
# minimal requirements check
PreCheck()
{
# If not Intel based
if [[ "$(uname -m)" != 'x86_64' ]] && [[ "$(uname -m)" != 'i386' ]]
then
die "This script is for Debian/RedHat/Arch/SUSE/Gentoo/Slackware/Void/KaOS/Deepin/Kwort/Pisi/NuTyx/Clear/NixOS/Mariner Linux Intel based flavours only"
fi
# fills in distribution variables
getDistro "$1"
# if VPN or VPNIP empty, aborts
if [[ -z "${VPN}" ]] || [[ -z "${VPNIP}" ]]
then
# and not handling uninstall or selfupdate, abort
[[ "$1" != "uninstall" ]] && [[ "$1" != "selfupdate" ]] && [[ "$1" != "rmchroot" ]] && die "Run vpn.sh -i --vpn=FQDN or fill in VPN and VPNIP with the DNS FQDN and the IP address of your Checkpoint VPN server"
fi
# if not root/sudo
if [[ "${EUID}" -ne 0 ]]
then
# This script needs a user with sudo privileges
command -v sudo &>/dev/null || die "install sudo and configure sudoers/groups for this user"
# The user needs sudo privileges
[[ $(sudo -l) != *"not allowed"* ]] || die "configure sudoers/groups for this user"
# for using/relaunching
# self-promoting script to sudo
# recursively call the script with sudo
# hence no needing sudo before the command
exec sudo -sE "$0" "${args[@]}"
else
# This script might need a user with sudo privileges
command -v sudo &>/dev/null || echo "you might want to install sudo" >&2
fi
}
# wrapper for chroot
doChroot()
{
# setarch i386 lies to uname about being 32 bits
# clean LD_PRELOAD (PCLinuxOS bug)
# you dont want to inherit it inside the chroot
# NuTyx bug? conflits with BusyBox
if [[ ${NUTYX} -eq 1 ]]
then
LD_PRELOAD="" /usr/bin/setarch i386 chroot "${CHROOT}" "$@"
else
LD_PRELOAD="" setarch i386 chroot "${CHROOT}" "$@"
fi
}
# C/Unix convention - 0 success, 1 failure
isCShellRunning()
{
pgrep -f CShell &> /dev/null
return $?
}
# no mount --fstab
#mountChroot()
#{
# local line
# local mtpoint
# local trash
# local fsoptions
#
# while read -r fs mtpoint trash fsoptions trash trash;
# do
# [[ -e "$fs" ]] && mount -o $fsoptions "$fs" "$mtpoint"
# done < "${CHROOT}/etc/fstab"
#}
# mount Chroot filesystems
mountChrootFS()
{
# if CShell running, they are mounted
if ! isCShellRunning
then
# mounts chroot filesystems
# if not mounted
mount | grep "${CHROOT}" &> /dev/null
if [[ $? -eq 1 ]]
then
# consistency checks
[[ ! -f "${CHROOT}/etc/fstab" ]] && die "no ${CHROOT}/etc/fstab"
# mounts using fstab inside chroot, all filesystems
# [[ ${ALPINE} -eq 0 ]] && mount --fstab "${CHROOT}/etc/fstab" -a
# [[ ${ALPINE} -eq 1 ]] && mountChroot
# NuTyx bug? Conflits with BusyBox
if [[ ${NUTYX} -eq 1 ]]
then
/bin/mount --fstab "${CHROOT}/etc/fstab" -a
else
mount --fstab "${CHROOT}/etc/fstab" -a
fi
# /run/nscd cant be shared between host and chroot
# for it to not share socket
if [[ -d /run/nscd ]]
then
mkdir -p "${CHROOT}/nscd"
mount --bind "${CHROOT}/nscd" "${CHROOT}/run/nscd"
fi
# lax double check
if ! mount | grep "${CHROOT}" &> /dev/null
then
die "mount failed"
fi
fi
fi
}
# umount chroot fs
umountChrootFS()
{
# unmounts chroot filesystems
# if mounted
if mount | grep "${CHROOT}" &> /dev/null
then
# there is no --fstab for umount
# we dont want to abort if not present
[[ -f "${CHROOT}/etc/fstab" ]] && doChroot /usr/bin/umount -a 2> /dev/null
# umounts any leftover mount
for i in $(mount | grep "${CHROOT}" | awk ' { print $3 } ' )
do
umount "$i" 2> /dev/null
umount -l "$i" 2> /dev/null
done
# force umounts any leftover mount
for i in $(mount | grep "${CHROOT}" | awk ' { print $3 } ' )
do
umount -l "$i" 2> /dev/null
done
fi
}
# Firefox Policy
# adds X.509 self-signed CShell certificate
# to the list of accepted enterprise root certificates
#
# Argument: $1 = Directory for installing policy
#
# CShell localhost certificate accepted automatically using Firefox
# if this policy installed
#
FirefoxJSONpolicy()
{
cat <<-EOF14 > "$1/policies.json"
{
"policies": {
"ImportEnterpriseRoots": true,
"Certificates": {
"Install": [
"${CHROOT}/usr/bin/cshell/cert/CShell_Certificate.crt"
]
}
}
}
EOF14
}
#
# installs Firefox policy accepting
# CShell localhost certificate
# in the host machine
#
# Argument:
# $1 == install : install policy file(s)
# $1 == uninstall : remove policy file(s)
#
FirefoxPolicy()
{
local DIR
local PolInstalled
# flag as not installed
PolInstalled=0
if [[ "$1" == "install" ]]
then
# for Firefox SNAPs
[[ -d "/etc/firefox" ]] && [[ ! -d "/etc/firefox/policies" ]] && mkdir /etc/firefox/policies 2> /dev/null
# code for Void, Arch, Slackware, ALT Linux, KaOS, Firefox SNAPs, BOSS, PakOS, NavyLinux
for i in "/usr/lib64/firefox" "/usr/lib/firefox" "/usr/lib64/firefox" "/opt/firefox" "/opt/moz/firefox" "/usr/lib64/mozilla"
do
[[ ! -d "$i/distribution" ]] && mkdir "$i/distribution" 2> /dev/null
done
fi
# if Firefox installed
# cycle possible firefox global directories
for DIR in "/etc/firefox/policies" $(find /usr/lib/*firefox*/distribution /usr/lib64/*firefox*/distribution /usr/share/*firefox*/distribution /opt/*firefox*/distribution /opt/moz/*firefox*/distribution /usr/lib64/*mozilla* -type d -maxdepth 0 2> /dev/null)
do
# -d ${DIR} double check, mostly redundant check
if [[ "$1" == "install" ]] && [[ -d "${DIR}" ]]
then
# if policies file not already installed
if [[ ! -f "${DIR}/policies.json" ]] || grep CShell_Certificate "${DIR}/policies.json" &> /dev/null
then
# can't be sure for snap
# so don't flag as policy installed
# for it to warn for accepting certificate
if [[ "${DIR}" != "/etc/firefox/policies" ]]
then
# flag as installed
PolInstalled=1
fi
# creates JSON policy file
# Accepting CShell certificate
FirefoxJSONpolicy "${DIR}"
echo "Policy installed: ${DIR}/policies.json" >&2
else
echo "Another policy already found: ${DIR}/policies.json" >&2
fi
fi
# deletes previous installed Firefox policy for accepting localhost CShell certificate
if [[ "$1" == "uninstall" ]] && grep CShell_Certificate "${DIR}/policies.json" &> /dev/null
then
rm -f "${DIR}/policies.json"
fi
done
# if Firefox policy installed
# "install" implied, Pollinstalled cant be 1 otherwise
if [[ "$PolInstalled" -eq 1 ]]
then
# if Firefox running, kill it
pgrep -f firefox &>/dev/null && pkill -9 -f firefox
echo "Firefox policy created for accepting https://localhost:14186 certificate" >&2
echo "If using other browser than Firefox or Firefox is a snap" >&2
else
[[ "$1" == "install" ]] && echo "No Firefox policy installed" >&2
fi
}
#
# Client wrapper section
#
# split command
#
# split tunnel, only after VPN is up
# if VPN is giving "wrong routes"
# deleting the default VPN gateway mith not be enough
# so there is a need to fill in routes in the SPLIT variable
# at /opt/etc/vpn.conf
# or if before install it, at the beginning of this script
#
Split()
{
# if SPLIT empty
if [[ -z "${SPLIT+x}" ]]
then
echo "If this does not work, please fill in SPLIT with a network/mask list eg flush +x.x.x.x/x -x.x.x.x/x" >&2
echo "either in ${CONFFILE} or in ${SCRIPTNAME}" >&2
# deletes default gw into VPN
ip route delete 0.0.0.0/1
echo "default VPN gateway deleted" >&2
else
# gets local VPN given IP address
IP=$(ip -4 addr show "${TUNSNX}" | awk '/inet/ { print $2 } ')
[ -z "$IP" ] && die "do split only after VPN tunnel is up"
# not hardcoded anymore
#
# cleans all VPN routes
# cleans all routes given to tunsnx interface
#ip route flush table main dev "${TUNSNX}"
# creates new VPN routes according to $SPLIT
# don't put ""
# new format
# for instance for split VPN with Internet access
#
# dropping all VPN routes
# add route to 100.1.1.0/24 PUBLIC network address of VPN
# add route to 10.0.0.0/8 via VPN
#
# SPLIT="flush +100.1.1.0/24 +10.0.0.0/8"
#
for i in ${SPLIT}
do
case ${i::1} in
f)
# flush
# can be written flush instead of f in SPLIT for clarity
#
# cleans all VPN routes
# cleans all routes given to tunsnx interface
#
# beware that cleaning all routes you have a limited time
# to restore communication with the CheckPoint
# before tunnel tears down
# e.g. SPLIT better have a rule to restore a equivalent route
#
ip route flush table main dev "${TUNSNX}"
;;
+)
# for adding a route
#
ip route add "${i:1}" dev "${TUNSNX}" src "${IP}"
;;
-)
# for deleting a route
# for deleting default gw given by VPN
# -0.0.0.0/1
#
ip route delete "${i:1}" dev "${TUNSNX}" src "${IP}"
;;
*)
die "error in SPLIT format. If working in a previous version, SPLIT behaviour changed"
;;
esac
done
fi
}
# status command
showStatus()
{
local VER
if ! isCShellRunning
then
# chroot/mount down, etc, not showing status
die "CShell not running"
else
echo "CShell running"
fi
# host / chroot arquitecture
echo
echo -n "System: "
awk -v ORS= -F"=" '/^PRETTY_NAME/ { gsub("\"","");print $2" " } ' /etc/os-release
#arch
echo -n "$(uname -m) "
uname -r
echo -n "Chroot: "
doChroot /bin/bash --login -pf <<-EOF2 | awk -v ORS= -F"=" '/^PRETTY_NAME/ { gsub("\"","");print $2" " } '
cat /etc/os-release
EOF2
# print--architecture and not uname because chroot shares the same kernel
doChroot /bin/bash --login -pf <<-EOF3
/usr/bin/dpkg --print-architecture
EOF3
# SNX version
echo
echo -n "SNX - installed "
doChroot snx -v 2> /dev/null | awk '/build/ { print $2 }'
echo -n "SNX - available for download "
# shellcheck disable=SC2086
if ! curl $CURL_OPT "https://${VPN}/SNX/CSHELL/snx_ver.txt" 2> /dev/null
then
# shellcheck disable=SC2086
curl $CURL_OPT "https://${VPN}/${SSLVPN}/SNX/CSHELL/snx_ver.txt" 2> /dev/null || echo "Could not get SNX download version" >&2
fi
# Mobile Access Portal Agent version installed
# we kept it earlier when installing
echo
if [[ -f "${CHROOT}/root/.cshell_ver.txt" ]]
then
echo -n "CShell - installed version "
cat "${CHROOT}/root/.cshell_ver.txt"
fi
echo -n "CShell - available for download "
# shellcheck disable=SC2086
if ! curl $CURL_OPT "https://${VPN}/SNX/CSHELL/cshell_ver.txt" 2> /dev/null
then
# shellcheck disable=SC2086
curl $CURL_OPT "https://${VPN}/${SSLVPN}/SNX/CSHELL/cshell_ver.txt" 2> /dev/null || echo "Could not get CShell download version" >&2
fi
# Mobile Access Portal Agent X.509 self-signed CA certificate
# localhost certificate
if [[ -f "${CHROOT}/usr/bin/cshell/cert/CShell_Certificate.crt" ]]
then
echo
echo "CShell localhost self-signed CA certificate"
echo
openssl x509 -in "${CHROOT}/usr/bin/cshell/cert/CShell_Certificate.crt" -text | grep -E ", CN = | Not [BA]"
fi
# show vpn.conf
echo
[[ -f "${CONFFILE}" ]] && cat "${CONFFILE}"
# IP connectivity
echo
# IP address VPN local address given
IP=""
IP=$(ip -4 addr show "${TUNSNX}" 2> /dev/null | awk '/inet/ { print $2 } ')
echo -n "Linux IP address: "
# print IP address linked to hostname
#hostname -I | awk '{print $1}'
ip a s |
sed -ne '
/127.0.0.1/!{
s/^[ \t]*inet[ \t]*\([0-9.]\+\)\/.*$/\1/p
}
'
echo
# if $IP not empty
# e.g. VPN up
#
if [[ -n "${IP}" ]]
then
echo "VPN on"
echo
echo "${TUNSNX} IP address: ${IP}"
# VPN mode test
# a configured proxy would defeat the test, so --no-proxy
# needs to test *direct* IP connectivity
# OS/ca-certificates package needs to be recent
# or otherwise, the OS CA root certificates chain file needs to be recent
echo