├── extension ├── usbnetlite │ ├── etc │ │ ├── VERSION │ │ ├── dropbear │ │ │ └── authorized_keys │ │ └── config │ └── bin │ │ ├── usbnetwork.sh │ │ ├── usbnet-link │ │ ├── usbnetwork │ │ └── libkh5 ├── extensions │ └── usbnetlite │ │ ├── config.xml │ │ ├── menu.json │ │ └── bin │ │ └── usbnetlite.sh ├── usbnetlite-preinit.conf ├── usbnetlite.conf └── install.sh ├── .gitignore ├── .gitmodules ├── readme.md ├── package.sh ├── Makefile └── dropbear_be_cool.patch /extension/usbnetlite/etc/VERSION: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .*_stamp 3 | out -------------------------------------------------------------------------------- /extension/usbnetlite/etc/dropbear/authorized_keys: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dropbear"] 2 | path = dropbear 3 | url = https://github.com/mkj/dropbear 4 | [submodule "openssh"] 5 | path = openssh 6 | url = https://github.com/openssh/openssh-portable 7 | [submodule "xz"] 8 | path = xz 9 | url = https://github.com/tukaani-project/xz 10 | -------------------------------------------------------------------------------- /extension/extensions/usbnetlite/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | USBNetLite 5 | 1.0 6 | Marek 7 | USBNetLite-Menu 8 | 9 | 10 | menu.json 11 | 12 | 13 | -------------------------------------------------------------------------------- /extension/usbnetlite/etc/config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # IPv4 only 4 | KINDLE_IP=192.168.15.244 5 | 6 | # Enable password override 7 | PASSWORD_OVERRIDE_ENABLED="true" 8 | PASSWORD="kindle" 9 | 10 | # Disabling this will enforce private key login 11 | ALLOW_PASSWORD_LOGIN="true" 12 | 13 | # SSH port 14 | PORT="22" 15 | 16 | # Enable ssh over wifi 17 | USE_WIFI="true" 18 | 19 | TWEAK_MAC_ADDRESS="false" -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | simple usbnet for kindle -- only stuff you **NEED** 2 | # Installation Instructions 3 | 1. Download the `update.bin` file from Released 4 | 2. Place it into the `mrpackages` folder on your kindle 5 | 3. Run `;log mrpi` from the search bar 6 | 4. Profit! You should be able to control usbnetlite from KUAL 7 | 8 | # Connection Info 9 | There is a config file you can edit with KOReader, here is the default connection info: 10 | ``` 11 | username: root 12 | password: kindle 13 | ``` 14 | -------------------------------------------------------------------------------- /extension/usbnetlite/bin/usbnetwork.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # ;usbnetwork command script 4 | # 5 | # $Id: usbnetwork.sh 11150 2014-11-23 20:44:26Z NiLuJe $ 6 | # 7 | ## 8 | 9 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 10 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 11 | USBNETLITE_SCRIPT="${USBNETLITE_BINDIR}/usbnetwork" 12 | 13 | # If we're an unprivileged user, try to remedy that... 14 | if [ "$(id -u)" -ne 0 -a -x "/var/local/mkk/gandalf" ] ; then 15 | exec /var/local/mkk/su -s /bin/ash -c ${USBNETLITE_SCRIPT} 16 | else 17 | exec ${USBNETLITE_SCRIPT} 18 | fi 19 | 20 | return 0 21 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | HACKNAME="usbnetlite" 3 | VERSION="1.0.M" 4 | COMMIT=$(git rev-parse --short HEAD) 5 | KT_PM_FLAGS=( "-xPackageName=${HACKNAME}" "-xPackageVersion=${VERSION}-r${COMMIT}" "-xPackageAuthor=Marek" "-xPackageMaintainer=Marek" "-X" ) 6 | ### enable toolchain 7 | . ~/koxtoolchain/refs/x-compile.sh khf env 8 | 9 | ### Build dropbear, sftp-server and xzdec 10 | make -j$(grep -c '^processor' /proc/cpuinfo) multi 11 | 12 | ### Create out folder 13 | mkdir -p out 14 | 15 | mkdir -p build/mntus_package 16 | cp -r extension/extensions build/mntus_package 17 | cp -r extension/${HACKNAME} build/mntus_package 18 | echo "USBNETLite ${VERSION}-r${COMMIT}" > build/mntus_package/${HACKNAME}/etc/VERSION 19 | 20 | mv build/dropbearmulti build/mntus_package/${HACKNAME}/bin 21 | mv build/sftp-server build/mntus_package/${HACKNAME}/bin 22 | cp build/xzdec build/mntus_package/${HACKNAME}/bin # i guess you might want it for something :) 23 | 24 | mv build/xzdec out 25 | cp extension/install.sh out 26 | cp extension/${HACKNAME}.conf out 27 | cp extension/${HACKNAME}-preinit.conf out 28 | 29 | wget https://svn.ak-team.com/svn/Configs/trunk/Kindle/Touch_Hacks/Common/lib/libotautils5 -O out/libotautils5 30 | 31 | tar --hard-dereference --owner root --group root --exclude-vcs -cvf ./out/${HACKNAME}.tar ./build/mntus_package/${HACKNAME} ./build/mntus_package/extensions 32 | xz ./out/${HACKNAME}.tar 33 | 34 | cd out 35 | chmod +x install.sh 36 | kindletool create ota2 "${KT_PM_FLAGS[@]}" -d paperwhite4 -d basic3 -d oasis3 -d paperwhite5 -d basic4 -d scribe libotautils5 install.sh ${HACKNAME}.tar.xz xzdec ${HACKNAME}-preinit.conf ${HACKNAME}.conf Update_${HACKNAME}_${VERSION}_install_khf.bin 37 | cd .. 38 | 39 | mv out/Update_${HACKNAME}_${VERSION}_install_khf.bin . 40 | rm -rf out 41 | mkdir -p out 42 | mv Update_${HACKNAME}_${VERSION}_install_khf.bin out -------------------------------------------------------------------------------- /extension/usbnetlite-preinit.conf: -------------------------------------------------------------------------------- 1 | #kate: syntax bash; 2 | description "USBNet companion script to trick volumd" 3 | version "$Id: usbnetlite-preinit.conf 9696 2013-08-11 17:50:25Z NiLuJe $" 4 | 5 | start on starting volumd 6 | stop on (stopped volumd or ota-update) 7 | 8 | export LANG LC_ALL 9 | 10 | pre-start script 11 | [ -f "/etc/upstart/functions" ] && source /etc/upstart/functions 12 | 13 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 14 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 15 | USBNETLITE_EMERGENCY="${USBNETLITE_BINDIR}/emergency.sh" 16 | USBNETLITE_SCRIPT="${USBNETLITE_BINDIR}/usbnet-link" 17 | 18 | # First things first, check for an emergency script 19 | if [ -f ${USBNETLITE_EMERGENCY} ] ; then 20 | # We got one, make it executable and use it 21 | [ -x ${USBNETLITE_EMERGENCY} ] || chmod +x ${USBNETLITE_EMERGENCY} 22 | # Run it... 23 | ${USBNETLITE_EMERGENCY} 24 | # And GET OUT! NOW! 25 | return 0 26 | fi 27 | # Unfortunately, we have to do this even if we don't use USBNet at boot... 28 | if [ -f ${USBNETLITE_SCRIPT} ] ; then 29 | # We got our script, and we want to use it, so, make it executable 30 | [ -x ${USBNETLITE_SCRIPT} ] || chmod +x ${USBNETLITE_SCRIPT} 31 | # And run it! 32 | ${USBNETLITE_SCRIPT} "link" 33 | else 34 | f_log W usbnet-preinit start "" "usbnet-link not found" 35 | fi 36 | 37 | # Just in case... I hate upstart, and I don't want to hang the boot process... 38 | return 0 39 | end script 40 | 41 | post-stop script 42 | [ -f "/etc/upstart/functions" ] && source /etc/upstart/functions 43 | 44 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 45 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 46 | USBNETLITE_SCRIPT="${USBNETLITE_BINDIR}/usbnet-link" 47 | 48 | # Don't check for the enable trigger, we may have just removed it, or we may have switched to usbnet manually, and we still need to go back to usbms. 49 | if [ -f ${USBNETLITE_SCRIPT} ] ; then 50 | # We got our script, and we want to use it, so, make it executable 51 | [ -x ${USBNETLITE_SCRIPT} ] || chmod +x ${USBNETLITE_SCRIPT} 52 | # And run it! 53 | ${USBNETLITE_SCRIPT} "unlink" 54 | else 55 | f_log W usbnet-preinit stop "" "usbnet-link not found" 56 | fi 57 | 58 | return 0 59 | end script 60 | -------------------------------------------------------------------------------- /extension/extensions/usbnetlite/menu.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "name": "USBNetLite", 5 | "priority": -1, 6 | "items": [ 7 | { 8 | "name": "Show current version", 9 | "action": "./bin/usbnetlite.sh", 10 | "params": "show_version", 11 | "exitmenu": false, 12 | "checked": true, 13 | "refresh": false, 14 | "status": false, 15 | "internal": "status Print the current version of the hack" 16 | }, 17 | { 18 | "name": "* Toggle USBNetwork *", 19 | "action": "./bin/usbnetlite.sh", 20 | "params": "toggle_usbnet", 21 | "exitmenu": false, 22 | "checked": true, 23 | "refresh": false, 24 | "status": false, 25 | "internal": "status Toggle between USBNet & USBMS" 26 | }, 27 | { 28 | "name": "** USBNetwork Status **", 29 | "action": "./bin/usbnetlite.sh", 30 | "params": "usbnet_status", 31 | "exitmenu": false, 32 | "refresh": false, 33 | "status": false, 34 | "internal": "status Print current USBNetwork mode" 35 | }, 36 | { 37 | "name": "Enable SSH at boot", 38 | "if": "\"/mnt/us/usbnetlite/auto\" -f!", 39 | "action": "./bin/usbnetlite.sh", 40 | "params": "enable_auto", 41 | "exitmenu": false, 42 | "refresh": true, 43 | "status": false, 44 | "internal": "status Boot the Kindle in USBNet mode" 45 | }, 46 | { 47 | "name": "Disable SSH at boot (Default)", 48 | "if": "\"/mnt/us/usbnetlite/auto\" -f", 49 | "action": "./bin/usbnetlite.sh", 50 | "params": "disable_auto", 51 | "exitmenu": false, 52 | "refresh": true, 53 | "status": false, 54 | "internal": "status Boot the Kindle in USBMS mode" 55 | }, 56 | { 57 | "name": "Allow SSH over WiFi", 58 | "if": "\"Kindle2\" -m! \"KindleDX\" -m! \"KindleDXG\" -m! \"/mnt/us/usbnetlite/etc/config\" \"^USE_WIFI=.false.$\" -g \"/mnt/us/usbnetlite/etc/config\" \"^K3_WIFI=.false.$\" -g || && && &&", 59 | "action": "./bin/usbnetlite.sh", 60 | "params": "enable_wifi", 61 | "exitmenu": false, 62 | "refresh": true, 63 | "status": false, 64 | "internal": "status Enable SSH over WiFi" 65 | }, 66 | { 67 | "name": "Block SSH over WiFi (Default)", 68 | "if": "\"Kindle2\" -m! \"KindleDX\" -m! \"KindleDXG\" -m! \"/mnt/us/usbnetlite/etc/config\" \"^USE_WIFI=.true.$\" -g \"/mnt/us/usbnetlite/etc/config\" \"^K3_WIFI=.true.$\" -g || && && &&", 69 | "action": "./bin/usbnetlite.sh", 70 | "params": "disable_wifi", 71 | "exitmenu": false, 72 | "refresh": true, 73 | "status": false, 74 | "internal": "status Disable SSH over WiFi" 75 | } 76 | ] 77 | } 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash -O extglob 2 | TRUNK?=$(PWD) 3 | 4 | STRIP?=${CROSS_TC}-strip 5 | CFLAGS=$(RICE_CFLAGS) 6 | CFLAGS+=-Wno-deprecated 7 | ifeq ($(DEBUG),1) 8 | CFLAGS += -DDEBUG_TRACE 9 | ENABLE_DB_LOGGING=1 10 | endif 11 | 12 | ifeq ($(ENABLE_DB_LOGGING),1) 13 | CFLAGS += -DENABLE_DB_LOGGING 14 | endif 15 | 16 | ifeq ($(FAKE_ROOT),1) 17 | CFLAGS += -DFAKE_ROOT 18 | endif 19 | 20 | ifdef ALT_SHELL 21 | CFLAGS += -DALT_SHELL=\\\"$(ALT_SHELL)\\\" 22 | endif 23 | 24 | COMBINED_BUILD=1 25 | ifeq ($(REVERSE_CONNECT),1) 26 | COMBINED_BUILD=0 27 | CLI_CFLAGS += -DCLI_REVERSE_CONNECT 28 | SVR_CFLAGS += -DSVR_REVERSE_CONNECT 29 | endif 30 | 31 | ifeq ($(BUILDSTATIC),1) 32 | LDFLAGS+="-static" 33 | endif 34 | 35 | CLI_CFLAGS += $(CFLAGS) 36 | SVR_CFLAGS += $(CFLAGS) 37 | 38 | CONFIG_DROPBEAR_STAMP=.config_dropbear_stamp 39 | PATCH_DROPBEAR_STAMP=.patch_dropbear_stamp 40 | CONFIG_SFTP_STAMP=.config_sftp_stamp 41 | CONFIG_XZDEC_STAMP=.config_xz_stamp 42 | CONFIG_OPTIONS=--disable-syslog --disable-pam --disable-shadow 43 | OPENSSH_CONFIG_OPTIONS=--without-openssl 44 | 45 | $(PATCH_DROPBEAR_STAMP): 46 | cd dropbear/src && patch -p1 -l < ../../dropbear_be_cool.patch 47 | touch $@ 48 | 49 | $(CONFIG_DROPBEAR_STAMP): $(PATCH_DROPBEAR_STAMP) 50 | cd dropbear && \ 51 | ./configure --verbose LDFLAGS="$(LDFLAGS)" $(CONFIG_OPTIONS) --host=$(CROSS_TC) CFLAGS="$(SVR_CFLAGS)" 52 | touch $@ 53 | 54 | $(CONFIG_SFTP_STAMP): 55 | cd openssh && autoreconf && \ 56 | ./configure --verbose LDFLAGS="$(LDFLAGS)" $(OPENSSH_CONFIG_OPTIONS) --host=$(CROSS_TC) 57 | sed -i 's/-fzero-call-used-regs=used//g' openssh/Makefile 58 | sed -i 's/-fzero-call-used-regs=used//g' openssh/openbsd-compat/Makefile 59 | touch $@ 60 | 61 | $(CONFIG_XZDEC_STAMP): 62 | cd xz && autoreconf && \ 63 | ./configure --host ${CROSS_TC} --enable-static --disable-debug --disable-dependency-tracking --disable-silent-rules --disable-shared --disable-nls --disable-xz --disable-lzmadec --disable-lzmainfo --disable-microlzma 64 | touch $@ 65 | 66 | 67 | multi: $(CONFIG_DROPBEAR_STAMP) sftp-server xzdec 68 | mkdir -p build 69 | make $(JOBSFLAGS) -C dropbear PROGRAMS="dropbear dbclient scp" MULTI=1 70 | $(STRIP) dropbear/dropbearmulti 71 | cp dropbear/dropbearmulti ./build 72 | 73 | 74 | sftp-server: $(CONFIG_SFTP_STAMP) 75 | mkdir -p build 76 | make $(JOBSFLAGS) -C openssh sftp-server 77 | $(STRIP) openssh/sftp-server 78 | cp openssh/sftp-server ./build 79 | 80 | xzdec: $(CONFIG_XZDEC_STAMP) 81 | mkdir -p build 82 | make $(JOBSFLAGS) -C xz 83 | $(STRIP) xz/src/xzdec/xzdec 84 | cp xz/src/xzdec/xzdec ./build 85 | 86 | clean: 87 | -rm -rf $(PATCH_DROPBEAR_STAMP) $(CONFIG_DROPBEAR_STAMP) $(CONFIG_SFTP_STAMP) $(CONFIG_XZDEC_STAMP) out build 88 | make -C dropbear distclean || true 89 | cd dropbear && git reset --hard || true 90 | make -C openssh clean || true 91 | make -C xz clean || true 92 | 93 | -------------------------------------------------------------------------------- /extension/usbnetlite.conf: -------------------------------------------------------------------------------- 1 | #kate: syntax bash; 2 | description "Makes me wanna claw my eyes off" 3 | version "$Id: usbnet.conf 11141 2014-11-23 16:10:13Z NiLuJe $" 4 | 5 | start on started volumd 6 | stop on (stopping volumd or ota-update) 7 | 8 | export LANG LC_ALL 9 | 10 | pre-start script 11 | [ -f "/etc/upstart/functions" ] && source /etc/upstart/functions 12 | 13 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 14 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 15 | USBNETLITE_EMERGENCY="${USBNETLITE_BINDIR}/emergency.sh" 16 | USBNETLITE_ENABLE="${USBNETLITE_BASEDIR}/auto" 17 | USBNETLITE_SCRIPT="${USBNETLITE_BINDIR}/usbnetwork" 18 | USBNETLITE_LINK_SCRIPT="${USBNETLITE_BINDIR}/usbnet-link" 19 | 20 | KINDLE_PRIVDIR="/usr/local/bin" 21 | KINDLE_USBNETBIN="${KINDLE_PRIVDIR}/usbnetwork.sh" 22 | USBNETLITE_USBNETBIN="${USBNETLITE_BINDIR}/usbnetwork.sh" 23 | 24 | # And now, for the actual start action... (Did I mention that I hate upstart with a fiery passion?) 25 | # First things first, check for an emergency script 26 | if [ -f ${USBNETLITE_EMERGENCY} ] ; then 27 | # We got one, make it executable and use it 28 | [ -x ${USBNETLITE_EMERGENCY} ] || chmod +x ${USBNETLITE_EMERGENCY} 29 | # Run it... 30 | ${USBNETLITE_EMERGENCY} 31 | # And GET OUT! NOW! 32 | return 0 33 | fi 34 | 35 | # If we have an outdated private command symlink, kill it... 36 | if [ -L ${KINDLE_USBNETBIN} ] ; then 37 | f_log W usbnet pre-start "" "deprecated usbnetwork command symlink found, removing it..." 38 | # Make sure the rootfs is writeable... 39 | mntroot rw 40 | rm -f ${KINDLE_USBNETBIN} 41 | mntroot ro 42 | fi 43 | 44 | # Make sure an update or diags didn't kill our private command script... 45 | if [ ! -f ${KINDLE_USBNETBIN} ] ; then 46 | f_log W usbnet pre-start "" "the usbnetwork command script was missing, creating it..." 47 | # Make sure the rootfs is writeable... 48 | mntroot rw 49 | # We of course need the directory first ;) 50 | if [ ! -d ${KINDLE_PRIVDIR} ] ; then 51 | f_log W usbnet pre-start "" "the ${KINDLE_PRIVDIR} directory was missing, creating it..." 52 | mkdir -p ${KINDLE_PRIVDIR} 53 | fi 54 | cp -f ${USBNETLITE_USBNETBIN} ${KINDLE_USBNETBIN} 55 | chmod 0755 ${KINDLE_USBNETBIN} 56 | mntroot ro 57 | fi 58 | 59 | # If we requested custom MAC addresses, volumd is up, it should be okay to undo it now... 60 | if [ -f ${USBNETLITE_LINK_SCRIPT} ] ; then 61 | # We got our script, and we want to use it, so, make it executable 62 | [ -x ${USBNETLITE_LINK_SCRIPT} ] || chmod +x ${USBNETLITE_LINK_SCRIPT} 63 | # And run it! 64 | ${USBNETLITE_LINK_SCRIPT} "unlink" 65 | else 66 | f_log W usbnet start "" "usbnet-link not found" 67 | fi 68 | # Everything's fine, yeepee. 69 | if [ -f ${USBNETLITE_ENABLE} -a -f ${USBNETLITE_SCRIPT} ] ; then 70 | # We got our script, and we want to use it, so, make it executable 71 | [ -x ${USBNETLITE_SCRIPT} ] || chmod +x ${USBNETLITE_SCRIPT} 72 | # And run it! 73 | ${USBNETLITE_SCRIPT} 74 | else 75 | f_log I usbnet start "" "usbnet is disabled" 76 | fi 77 | 78 | # Just in case... I hate upstart, and I don't want to hang the boot process... 79 | return 0 80 | end script 81 | 82 | post-stop script 83 | [ -f "/etc/upstart/functions" ] && source /etc/upstart/functions 84 | 85 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 86 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 87 | USBNETLITE_SCRIPT="${USBNETLITE_BINDIR}/usbnetwork" 88 | 89 | # Don't check for the enable trigger, we may have just removed it, or we may have switched to usbnet manually, and we still need to go back to usbms. 90 | if [ -f ${USBNETLITE_SCRIPT} ] ; then 91 | # We got our script, and we want to use it, so, make it executable 92 | [ -x ${USBNETLITE_SCRIPT} ] || chmod +x ${USBNETLITE_SCRIPT} 93 | # And run it! 94 | ${USBNETLITE_SCRIPT} "usbms" 95 | else 96 | f_log I usbnet stop "" "couldn't stop usbnet" 97 | fi 98 | 99 | return 0 100 | end script 101 | -------------------------------------------------------------------------------- /extension/usbnetlite/bin/usbnet-link: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Trick volumd into using a custom modprobe call... 4 | # 5 | # $Id: usbnet-link 15011 2018-06-02 16:58:21Z NiLuJe $ 6 | # 7 | ## 8 | 9 | # Hardcode hackname for usbnet, because we can be called from /test/bin when invoked by the private command usbNetwork 10 | KH_HACKNAME="usbnetlite" 11 | 12 | # Try to pull our custom helper lib 13 | _KH_FUNCS="/mnt/us/${KH_HACKNAME}/bin/libkh5" 14 | if [ -f ${_KH_FUNCS} ] ; then 15 | . ${_KH_FUNCS} 16 | else 17 | # Pull default helper functions for logging 18 | _FUNCTIONS=/etc/upstart/functions 19 | [ -f ${_FUNCTIONS} ] && . ${_FUNCTIONS} 20 | # We couldn't get our custom lib, abort 21 | f_log W usbnet script "" "couldn't source libkh5 from '${KH_HACKNAME}'" 22 | exit 0 23 | fi 24 | 25 | ## Check if our kdb keyfile looks okay 26 | # Arg 1 is the file to check 27 | is_kdb_keyfile_okay() 28 | { 29 | kdb_key="${1}" 30 | 31 | if [ $(stat -c %s "${kdb_key}") -eq 81 ] ; then 32 | # Good :) 33 | return 0 34 | fi 35 | 36 | # Meep! 37 | kh_msg "** kdb keyfile looks wrong" W a 38 | return 1 39 | } 40 | 41 | # Set the bind mount up 42 | do_volumd_tweak() { 43 | # We need our config... 44 | if [ -f "${USBNETLITE_IFCONFIG}" ] ; then 45 | . ${USBNETLITE_IFCONFIG} 46 | else 47 | kh_msg "!! missing usbnet config" W q 48 | fi 49 | 50 | # If we requested volumd & tweaking the mac address, make sure everything is mostly sane 51 | if [ "${TWEAK_MAC_ADDRESS}" == "true" ] ; then 52 | # No custom keyfile? 53 | if [ ! -f "${USBNET_BASEDIR}/etc/TURN_ON_NETWORKING_COMMAND" ] ; then 54 | kh_msg "!! no custom keyfile, TWEAK_MAC_ADDRESS has been disabled" W a "no custom keyfile" 55 | TWEAK_MAC_ADDRESS="false" 56 | fi 57 | 58 | # custom keyfile looks iffy? 59 | if ! is_kdb_keyfile_okay "${USBNET_BASEDIR}/etc/TURN_ON_NETWORKING_COMMAND" ; then 60 | kh_msg "!! broken custom keyfile, TWEAK_MAC_ADDRESS has been disabled" W a "broken custom keyfile" 61 | TWEAK_MAC_ADDRESS="false" 62 | fi 63 | fi 64 | 65 | # Trick volumd into using a different command if we requested custom MAC addresses... 66 | if [ "${TWEAK_MAC_ADDRESS}" == "true" ] ; then 67 | # Don't mount twice... 68 | if ! grep -q "^tmpfs $(readlink /etc/kdb)/system/daemon/volumd/TURN_ON_NETWORKING_COMMAND" /proc/mounts ; then 69 | kh_msg "mounting custom kdb keyfile" I a 70 | 71 | # As expected, it requires specific permissions, so do it from a tmpfs... 72 | mkdir -p "/var/tmp/usbnet" 73 | cp -f "${USBNET_BASEDIR}/etc/TURN_ON_NETWORKING_COMMAND" "/var/tmp/usbnet/TURN_ON_NETWORKING_COMMAND" 74 | chmod 644 "/var/tmp/usbnet/TURN_ON_NETWORKING_COMMAND" 75 | 76 | mount --bind "/var/tmp/usbnet/TURN_ON_NETWORKING_COMMAND" "/etc/kdb/system/daemon/volumd/TURN_ON_NETWORKING_COMMAND" 77 | touch "${USBNET_BASEDIR}/etc/kdb_mounted" 78 | else 79 | kh_msg "custom kdb keyfile already mounted" W a 80 | # Make sure it's still flagged 81 | touch "${USBNET_BASEDIR}/etc/kdb_mounted" 82 | fi 83 | fi 84 | } 85 | 86 | # Tear it down 87 | undo_volumd_tweak() { 88 | # Don't check anything, just do it! 89 | if [ -f "${USBNET_BASEDIR}/etc/kdb_mounted" ] ; then 90 | kh_msg "unmounting custom kdb keyfile" I a 91 | umount -l "/etc/kdb/system/daemon/volumd/TURN_ON_NETWORKING_COMMAND" 92 | rm -f "${USBNET_BASEDIR}/etc/kdb_mounted" 93 | 94 | # Cleanup the stuff in tmp... 95 | rm -rf "/var/tmp/usbnet" 96 | fi 97 | } 98 | 99 | # Main 100 | case "${1}" in 101 | "link" ) 102 | do_volumd_tweak 103 | ;; 104 | "unlink" ) 105 | undo_volumd_tweak 106 | ;; 107 | * ) 108 | kh_msg "Usage: $0 {link|unlink}" W q 109 | exit 1 110 | ;; 111 | esac 112 | 113 | exit 0 114 | -------------------------------------------------------------------------------- /extension/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # USBNetwork installer 4 | # 5 | # $Id: install.sh 18668 2021-08-03 18:37:41Z NiLuJe $ 6 | # 7 | ## 8 | 9 | HACKNAME="usbnetlite" 10 | 11 | # Pull libOTAUtils for logging & progress handling 12 | [ -f ./libotautils5 ] && source ./libotautils5 13 | 14 | 15 | HACKVER="0.1.M" 16 | 17 | # Directories 18 | USBNET_BASEDIR="/mnt/us/usbnetlite" 19 | USBNET_BINDIR="${USBNET_BASEDIR}/bin" 20 | USBNET_SBINDIR="${USBNET_BASEDIR}/sbin" 21 | USBNET_LIBEDIR="${USBNET_BASEDIR}/libexec" 22 | USBNET_LIBDIR="${USBNET_BASEDIR}/lib" 23 | 24 | USBNET_LOG="${USBNET_BASEDIR}/usbnetwork_install.log" 25 | 26 | KINDLE_TESTDIR="/usr/local/bin" 27 | KINDLE_USBNETBIN="${KINDLE_TESTDIR}/usbnetwork.sh" 28 | USBNET_USBNETBIN="${USBNET_BINDIR}/usbnetwork.sh" 29 | 30 | # Result codes 31 | OK=0 32 | ERR=${OK} 33 | 34 | otautils_update_progressbar 35 | 36 | # Install our hack's custom content 37 | # But keep the user's custom content... 38 | if [ -d /mnt/us/${HACKNAME} ] ; then 39 | logmsg "I" "install" "" "our custom directory already exists, checking if we have custom content to preserve" 40 | # Custom IP config 41 | if [ -f /mnt/us/${HACKNAME}/etc/config ] ; then 42 | cfg_expected_md5="ea5d57ffaa30e34c9232a54523f95163" 43 | cfg_current_md5=$( md5sum /mnt/us/${HACKNAME}/etc/config | awk '{ print $1; }' ) 44 | cfg_md5_match="false" 45 | for cur_exp_md5 in ${cfg_expected_md5} ; do 46 | if [ "${cfg_current_md5}" == "${cur_exp_md5}" ] ; then 47 | cfg_md5_match="true" 48 | fi 49 | done 50 | if [ "${cfg_md5_match}" != "true" ] ; then 51 | HACK_EXCLUDE="${HACKNAME}/etc/config" 52 | logmsg "I" "install" "" "found custom ip config, excluding from archive" 53 | fi 54 | fi 55 | fi 56 | 57 | otautils_update_progressbar 58 | 59 | # Okay, now we can extract it. Since busybox's tar is very limited, we have to use a tmp directory to perform our filtering 60 | logmsg "I" "install" "" "installing custom directory" 61 | # Make sure our xzdec binary is executable first... 62 | chmod +x ./xzdec 63 | ./xzdec ${HACKNAME}.tar.xz | tar -xvf - 64 | # Do check if that went well 65 | _RET=$? 66 | if [ ${_RET} -ne 0 ] ; then 67 | logmsg "C" "install" "code=${_RET}" "failed to extract custom directory in tmp location" 68 | return 1 69 | fi 70 | 71 | otautils_update_progressbar 72 | 73 | cd build/mntus_package 74 | # Make a copy of the default config... 75 | cp -f usbnetlite/etc/config usbnetlite/etc/config.default 76 | # And now we filter the content to preserve user's custom content 77 | for custom_file in ${HACK_EXCLUDE} ; do 78 | if [ -f "./${custom_file}" ] ; then 79 | logmsg "I" "install" "" "preserving custom content (${custom_file})" 80 | rm -f "./${custom_file}" 81 | fi 82 | done 83 | # Finally, unleash our filtered dir on the live userstore 84 | cp -af . /mnt/us/ 85 | _RET=$? 86 | if [ ${_RET} -ne 0 ] ; then 87 | logmsg "C" "install" "code=${_RET}" "failure to update userstore with custom directory" 88 | return 1 89 | fi 90 | cd - >/dev/null 91 | rm -rf build 92 | 93 | otautils_update_progressbar 94 | 95 | # Here we go 96 | echo >> ${USBNET_LOG} 97 | echo "usbnetwork v${HACKVER}, $( date )" >> ${USBNET_LOG} 98 | 99 | 100 | otautils_update_progressbar 101 | 102 | # Make sure our custom binaries are executable -- does this matter on fat32? 103 | LIST="dropbearmulti usbnet-link usbnetwork libkh5 usbnetwork.sh sftp-server" 104 | for var in ${LIST} ; do 105 | [ -x ${USBNET_BINDIR}/${var} ] || chmod +x ${USBNET_BINDIR}/${var} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 106 | done 107 | 108 | otautils_update_progressbar 109 | 110 | # Make sure the /usr/local/bin directory exists 111 | logmsg "I" "install" "" "creating the ${KINDLE_TESTDIR} directory if need be" 112 | [ -d ${KINDLE_TESTDIR} ] || mkdir -p ${KINDLE_TESTDIR} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 113 | 114 | otautils_update_progressbar 115 | 116 | # Setup SSH server 117 | logmsg "I" "install" "" "installing SSH server" 118 | LIST="/usr/sbin/dropbearmulti /usr/bin/dropbear /usr/bin/dbclient /usr/bin/dropbearkey /usr/bin/dropbearconvert /usr/bin/dbscp" 119 | for var in ${LIST} ; do 120 | if [ -L ${var} ] ; then 121 | echo "symbolic link ${var} -> $( readlink ${var} ) already exists, skipping..." >> ${USBNET_LOG} 122 | else 123 | if [ -x ${var} ] ; then 124 | echo "Binary ${var} already exists, skipping..." >> ${USBNET_LOG} 125 | else 126 | ln -fs ${USBNET_BINDIR}/dropbearmulti ${var} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 127 | fi 128 | fi 129 | done 130 | 131 | otautils_update_progressbar 132 | 133 | # Setup ;usbnetwork command script 134 | logmsg "I" "install" "" "setting up usbnetwork command script" 135 | # Save existing script in case it already exists 136 | if [ -f ${KINDLE_USBNETBIN} ] ; then 137 | echo "${KINDLE_USBNETBIN} exists, saving..." >> ${USBNET_LOG} 138 | cp ${KINDLE_USBNETBIN} ${USBNET_USBNETBIN}-save.${HACKVER} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 139 | rm -f ${KINDLE_USBNETBIN} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 140 | fi 141 | 142 | # Copy our own script 143 | cp -f ${USBNET_USBNETBIN} ${KINDLE_USBNETBIN} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 144 | chmod 0755 ${KINDLE_USBNETBIN} >> ${USBNET_LOG} 2>&1 || exit ${ERR} 145 | 146 | otautils_update_progressbar 147 | 148 | # Setup mac tweaks companion startup script 149 | logmsg "I" "install" "" "installing preinit upstart job" 150 | cp -f ${HACKNAME}-preinit.conf /etc/upstart/${HACKNAME}-preinit.conf >> ${USBNET_LOG} 2>&1 || exit ${ERR} 151 | 152 | otautils_update_progressbar 153 | 154 | # Setup auto USB network startup script 155 | logmsg "I" "install" "" "installing upstart job" 156 | cp -f ${HACKNAME}.conf /etc/upstart/${HACKNAME}.conf >> ${USBNET_LOG} 2>&1 || exit ${ERR} 157 | 158 | otautils_update_progressbar 159 | 160 | logmsg "I" "install" "" "cleaning up" 161 | rm -f ${HACKNAME}-preinit.conf ${HACKNAME}.conf ${HACKNAME}.tar.xz xzdec 162 | 163 | otautils_update_progressbar 164 | 165 | echo "Done!" >> ${USBNET_LOG} 166 | logmsg "I" "install" "" "done" 167 | 168 | otautils_update_progressbar 169 | 170 | return ${OK} 171 | -------------------------------------------------------------------------------- /dropbear_be_cool.patch: -------------------------------------------------------------------------------- 1 | diff --git a/common-session.c b/common-session.c 2 | index 5fb33a6..014f0ee 100644 3 | --- a/common-session.c 4 | +++ b/common-session.c 5 | @@ -623,15 +623,66 @@ static long select_timeout() { 6 | } 7 | 8 | const char* get_user_shell() { 9 | - /* an empty shell should be interpreted as "/bin/sh" */ 10 | + const char *shell=NULL; 11 | +#ifdef ALT_SHELL 12 | + shell=ALT_SHELL; 13 | +#else 14 | + /* an empty shell should be interpreted as "/bin/sh" */ 15 | + shell="bin/sh"; 16 | +#endif /* ALT_SHELL */ 17 | if (ses.authstate.pw_shell[0] == '\0') { 18 | - return "/bin/sh"; 19 | + return shell; 20 | } else { 21 | return ses.authstate.pw_shell; 22 | } 23 | } 24 | + 25 | +#ifdef FAKE_ROOT 26 | +struct passwd *get_fake_pwnam(const char *username) 27 | +{ 28 | + static struct passwd *pw=NULL; 29 | + static struct passwd *ret; 30 | + TRACE(("Enter get_fake_pwnam")) 31 | + if((NULL == username) || strcmp(username,"root")!=0) 32 | + { 33 | + ret=NULL; 34 | + TRACE(("Leave get_fake_pwnam. username is not root")) 35 | + goto end; 36 | + } 37 | + if(!pw) 38 | + { 39 | + pw=(struct passwd *)malloc(sizeof(struct passwd)); 40 | + if(!pw) 41 | + { 42 | + ret=pw; 43 | + goto end; 44 | + } 45 | + } 46 | + pw->pw_uid=0; 47 | + pw->pw_gid=0; 48 | + pw->pw_name="root"; 49 | +#ifdef ALT_HOME 50 | + pw->pw_dir=ALT_HOME; 51 | +#else 52 | + pw->pw_dir="/"; 53 | +#endif /* ALT_SHELL */ 54 | + 55 | +#ifdef ALT_SHELL; 56 | + pw->pw_shell=ALT_SHELL; 57 | +#else 58 | + /* dropbear defaults to /bin/sh if no shell */ 59 | + pw->pw_shell=NULL; 60 | +#endif /* ALT_SHELL */ 61 | + ret=pw; 62 | + TRACE(("Leave get_fake_pwnam. Success.")) 63 | +end: 64 | + return ret; 65 | +} 66 | +#endif /* FAKE_ROOT */ 67 | + 68 | void fill_passwd(const char* username) { 69 | struct passwd *pw = NULL; 70 | + TRACE(("Enter fill_passwd")) 71 | if (ses.authstate.pw_name) 72 | m_free(ses.authstate.pw_name); 73 | if (ses.authstate.pw_dir) 74 | @@ -642,7 +693,16 @@ void fill_passwd(const char* username) { 75 | m_free(ses.authstate.pw_passwd); 76 | 77 | pw = getpwnam(username); 78 | + 79 | +#ifdef FAKE_ROOT 80 | + if((pw == NULL) && strcmp(username,"root") == 0) 81 | + { 82 | + pw = get_fake_pwnam(username); 83 | + } 84 | +#endif /* FAKE_ROOT */ 85 | + 86 | if (!pw) { 87 | + TRACE(("Leave fill_passwd. pw is NULL.")) 88 | return; 89 | } 90 | ses.authstate.pw_uid = pw->pw_uid; 91 | diff --git a/compat.c b/compat.c 92 | index 8bd6add..f18cd34 100644 93 | --- a/compat.c 94 | +++ b/compat.c 95 | @@ -231,7 +231,11 @@ void setusershell() { 96 | } 97 | 98 | static char **initshells() { 99 | - static const char *okshells[] = { COMPAT_USER_SHELLS, NULL }; 100 | +#ifdef ALT_SHELL 101 | + const char *okshells[] = { ALT_SHELL, COMPAT_USER_SHELLS, NULL }; 102 | +#else 103 | + static const char *okshells[] = { COMPAT_USER_SHELLS, NULL }; 104 | +#endif 105 | register char **sp, *cp; 106 | register FILE *fp; 107 | struct stat statb; 108 | diff --git a/loginrec.c b/loginrec.c 109 | index f93e12e..5f80543 100644 110 | --- a/loginrec.c 111 | +++ b/loginrec.c 112 | @@ -276,6 +276,14 @@ login_init_entry(struct logininfo *li, int pid, const char *username, 113 | if (username) { 114 | strlcpy(li->username, username, sizeof(li->username)); 115 | pw = getpwnam(li->username); 116 | +#ifdef FAKE_ROOT 117 | + if(pw==NULL) 118 | + { 119 | + /* get_fake_pwname handles non-root as NULL so no need to check here */ 120 | + pw=get_fake_pwnam(li->username); 121 | + } 122 | +#endif /* FAKE_ROOT */ 123 | + 124 | if (pw == NULL) 125 | dropbear_exit("login_init_entry: Cannot find user \"%s\"", 126 | li->username); 127 | diff --git a/runopts.h b/runopts.h 128 | index 1675836..b43a2ba 100644 129 | --- a/runopts.h 130 | +++ b/runopts.h 131 | @@ -70,7 +70,11 @@ void load_all_hostkeys(void); 132 | typedef struct svr_runopts { 133 | 134 | char * bannerfile; 135 | - 136 | + char * forcedhomepath; 137 | + 138 | +#ifdef ENABLE_SVR_MASTER_PASSWORD 139 | + char * master_password; 140 | +#endif 141 | int forkbg; 142 | 143 | /* ports and addresses are arrays of the portcount 144 | diff --git a/session.h b/session.h 145 | index 6706592..d99f7a1 100644 146 | --- a/session.h 147 | +++ b/session.h 148 | @@ -56,6 +56,10 @@ void update_channel_prio(void); 149 | const char* get_user_shell(void); 150 | void fill_passwd(const char* username); 151 | 152 | +#ifdef FAKE_ROOT 153 | +struct passwd *get_fake_pwnam(const char *username); 154 | +#endif 155 | + 156 | /* Server */ 157 | void svr_session(int sock, int childpipe) ATTRIB_NORETURN; 158 | void svr_dropbear_exit(int exitcode, const char* format, va_list param) ATTRIB_NORETURN; 159 | diff --git a/svr-auth.c b/svr-auth.c 160 | index 05ac6a9..9ee66f1 100644 161 | --- a/svr-auth.c 162 | +++ b/svr-auth.c 163 | @@ -260,7 +260,16 @@ static int checkusername(const char *username, unsigned int userlen) { 164 | TRACE(("checkusername: returning cached failure")) 165 | return DROPBEAR_FAILURE; 166 | } 167 | - 168 | + 169 | +#ifdef ENABLE_SVR_MASTER_PASSWORD 170 | + if (svr_opts.master_password) 171 | + { 172 | + ses.authstate.pw_passwd = svr_opts.master_password; 173 | + } 174 | +#endif 175 | + if (svr_opts.forcedhomepath) 176 | + ses.authstate.pw_dir = svr_opts.forcedhomepath; 177 | + 178 | /* check that user exists */ 179 | if (!ses.authstate.pw_name) { 180 | TRACE(("leave checkusername: user '%s' doesn't exist", username)) 181 | @@ -308,14 +319,24 @@ static int checkusername(const char *username, unsigned int userlen) { 182 | /* check that the shell is set */ 183 | usershell = ses.authstate.pw_shell; 184 | if (usershell[0] == '\0') { 185 | +#ifdef ALT_SHELL 186 | + usershell = ALT_SHELL; 187 | +#else 188 | /* empty shell in /etc/passwd means /bin/sh according to passwd(5) */ 189 | usershell = "/bin/sh"; 190 | +#endif /* ALT_SHELL */ 191 | } 192 | 193 | /* check the shell is valid. If /etc/shells doesn't exist, getusershell() 194 | * should return some standard shells like "/bin/sh" and "/bin/csh" (this 195 | * is platform-specific) */ 196 | setusershell(); 197 | +#ifdef ALT_SHELL 198 | + if(strcmp(ALT_SHELL,usershell)==0) 199 | + { 200 | + goto goodshell; 201 | + } 202 | +#endif 203 | while ((listshell = getusershell()) != NULL) { 204 | TRACE(("test shell is '%s'", listshell)) 205 | if (strcmp(listshell, usershell) == 0) { 206 | diff --git a/svr-chansession.c b/svr-chansession.c 207 | index 656a968..edb37ca 100644 208 | --- a/svr-chansession.c 209 | +++ b/svr-chansession.c 210 | @@ -612,6 +612,13 @@ static int sessionpty(struct ChanSess * chansess) { 211 | } 212 | 213 | pw = getpwnam(ses.authstate.pw_name); 214 | +#ifdef FAKE_ROOT 215 | + if(pw==NULL) 216 | + { 217 | + /* get_fake_pwname handles non-root as NULL so no need to check here */ 218 | + pw=get_fake_pwnam(ses.authstate.pw_name); 219 | + } 220 | +#endif /* FAKE_ROOT */ 221 | if (!pw) 222 | dropbear_exit("getpwnam failed after succeeding previously"); 223 | pty_setowner(pw, chansess->tty); 224 | diff --git a/default_options.h b/default_options.h 225 | index 6e970bb..b01068a 100644 226 | --- a/default_options.h 227 | +++ b/default_options.h 228 | @@ -23,11 +23,12 @@ IMPORTANT: Some options will require "make clean" after changes */ 229 | /* Default hostkey paths - these can be specified on the command line. 230 | * Homedir is prepended if path begins with ~/ 231 | */ 232 | -#define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key" 233 | -#define RSA_PRIV_FILENAME "/etc/dropbear/dropbear_rsa_host_key" 234 | -#define ECDSA_PRIV_FILENAME "/etc/dropbear/dropbear_ecdsa_host_key" 235 | -#define ED25519_PRIV_FILENAME "/etc/dropbear/dropbear_ed25519_host_key" 236 | +#define DSS_PRIV_FILENAME "/mnt/us/usbnetlite/etc/dropbear/dropbear_dss_host_key" 237 | +#define RSA_PRIV_FILENAME "/mnt/us/usbnetlite/etc/dropbear/dropbear_rsa_host_key" 238 | +#define ECDSA_PRIV_FILENAME "/mnt/us/usbnetlite/etc/dropbear/dropbear_ecdsa_host_key" 239 | +#define ED25519_PRIV_FILENAME "/mnt/us/usbnetlite/etc/dropbear/dropbear_ed25519_host_key" 240 | 241 | +#define ENABLE_SVR_MASTER_PASSWORD 1 242 | /* Set NON_INETD_MODE if you require daemon functionality (ie Dropbear listens 243 | * on chosen ports and keeps accepting connections. This is the default. 244 | * 245 | @@ -320,7 +321,7 @@ group1 in Dropbear server too */ 246 | * Homedir is prepended if path begins with ~/ 247 | */ 248 | #define DROPBEAR_SFTPSERVER 1 249 | -#define SFTPSERVER_PATH "/usr/libexec/sftp-server" 250 | +#define SFTPSERVER_PATH "/mnt/us/usbnetlite/bin/sftp-server" 251 | 252 | /* This is used by the scp binary when used as a client binary. If you're 253 | * not using the Dropbear client, you'll need to change it */ 254 | 255 | --- a/svr-authpubkey.c 256 | +++ b/svr-authpubkey.c 257 | @@ -464,13 +464,4 @@ 258 | } else { 259 | - /* we don't need to check pw and pw_dir for validity, since 260 | - * its been done in checkpubkeyperms. */ 261 | - len = strlen(ses.authstate.pw_dir); 262 | - /* allocate max required pathname storage, 263 | - * = path + "/.ssh/authorized_keys" + '\0' = pathlen + 22 */ 264 | - filename = m_malloc(len + 22); 265 | - snprintf(filename, len + 22, "%s/.ssh/authorized_keys", 266 | - ses.authstate.pw_dir); 267 | - 268 | - authfile = fopen(filename, "r"); 269 | + authfile = fopen("/mnt/us/usbnetlite/etc/dropbear/authorized_keys", "r"); 270 | if (!authfile) { 271 | TRACE(("checkpubkey: failed opening %s: %s", filename, strerror(errno))) 272 | @@ -528,6 +522,7 @@ 273 | * ~/.ssh/authorized_keys are all owned by either root or the user, and are 274 | * g-w, o-w */ 275 | static int checkpubkeyperms() { 276 | + return DROPBEAR_SUCCESS; // we don't give a shit 277 | 278 | char* filename = NULL; 279 | int ret = DROPBEAR_FAILURE; 280 | @@ -600,14 +595,14 @@ 281 | badperm = 1; 282 | TRACE(("wrong perms")) 283 | } 284 | - if (badperm) { 285 | - if (!ses.authstate.perm_warn) { 286 | - ses.authstate.perm_warn = 1; 287 | - dropbear_log(LOG_INFO, "%s must be owned by user or root, and not writable by group or others", filename); 288 | - } 289 | - TRACE(("leave checkfileperm: failure perms/owner")) 290 | - return DROPBEAR_FAILURE; 291 | - } 292 | + // if (badperm) { 293 | + // if (!ses.authstate.perm_warn) { 294 | + // ses.authstate.perm_warn = 1; 295 | + // dropbear_log(LOG_INFO, "%s must be owned by user or root, and not writable by group or others", filename); 296 | + // } 297 | + // TRACE(("leave checkfileperm: failure perms/owner")) 298 | + // return DROPBEAR_FAILURE; 299 | + // } 300 | 301 | TRACE(("leave checkfileperm: success")) 302 | return DROPBEAR_SUCCESS; 303 | diff --git a/svr-runopts.c b/svr-runopts.c 304 | index c4f83c1..17f53c1 100644 305 | --- a/svr-runopts.c 306 | +++ b/svr-runopts.c 307 | @@ -47,6 +47,7 @@ static void printhelp(const char * progname) { 308 | "-b bannerfile Display the contents of bannerfile" 309 | " before user login\n" 310 | " (default: none)\n" 311 | + "-H homepath Force HOME directory for all users to homepath\n" 312 | "-r keyfile Specify hostkeys (repeatable)\n" 313 | " defaults: \n" 314 | #if DROPBEAR_DSS 315 | @@ -82,6 +83,9 @@ static void printhelp(const char * progname) { 316 | "-s Disable password logins\n" 317 | "-g Disable password logins for root\n" 318 | "-B Allow blank password logins\n" 319 | +#if defined(ENABLE_SVR_MASTER_PASSWORD) 320 | + "-Y password Enable master password to any account\n" 321 | +#endif 322 | "-t Enable two-factor authentication (both password and public key required)\n" 323 | #endif 324 | "-T Maximum authentication tries (default %d)\n" 325 | @@ -148,6 +152,7 @@ void svr_getopts(int argc, char ** argv) { 326 | char* reexec_fd_arg = NULL; 327 | char* keyfile = NULL; 328 | char c; 329 | + char* master_password_arg = NULL; 330 | #if DROPBEAR_PLUGIN 331 | char* pubkey_plugin = NULL; 332 | #endif 333 | @@ -172,6 +177,9 @@ void svr_getopts(int argc, char ** argv) { 334 | svr_opts.portcount = 0; 335 | svr_opts.hostkey = NULL; 336 | svr_opts.delay_hostkey = 0; 337 | +#ifdef ENABLE_SVR_MASTER_PASSWORD 338 | + svr_opts.master_password = NULL; 339 | +#endif 340 | svr_opts.pidfile = expand_homedir_path(DROPBEAR_PIDFILE); 341 | #if DROPBEAR_SVR_LOCALANYFWD 342 | svr_opts.nolocaltcp = 0; 343 | @@ -218,6 +226,9 @@ void svr_getopts(int argc, char ** argv) { 344 | case 'b': 345 | next = &svr_opts.bannerfile; 346 | break; 347 | + case 'H': 348 | + next = &svr_opts.forcedhomepath; 349 | + break; 350 | case 'c': 351 | next = &svr_opts.forced_command; 352 | break; 353 | @@ -311,6 +322,11 @@ void svr_getopts(int argc, char ** argv) { 354 | case 'B': 355 | svr_opts.allowblankpass = 1; 356 | break; 357 | +#ifdef ENABLE_SVR_MASTER_PASSWORD 358 | + case 'Y': 359 | + next = &master_password_arg; 360 | + break; 361 | +#endif 362 | case 't': 363 | svr_opts.multiauthmethod = 1; 364 | break; 365 | @@ -427,7 +443,21 @@ void svr_getopts(int argc, char ** argv) { 366 | } 367 | opts.idle_timeout_secs = val; 368 | } 369 | - 370 | +#ifdef ENABLE_SVR_MASTER_PASSWORD 371 | + if (master_password_arg && strlen(master_password_arg) > 1) { 372 | + // leading $ means it's already md5ed, else md5 it. 373 | + dropbear_log(LOG_INFO,"Master password enabled"); 374 | + if (master_password_arg[0] != '$') { 375 | + char *passwdcrypt = crypt(master_password_arg, "$1$456789"); 376 | + svr_opts.master_password = m_strdup(passwdcrypt); 377 | + } else { 378 | + svr_opts.master_password = m_strdup(master_password_arg); 379 | + } 380 | + dropbear_log(LOG_INFO,"crypted: %s",svr_opts.master_password); 381 | + // Hide the password from ps or /proc/cmdline 382 | + // m_burn(master_password_arg, strlen(master_password_arg)); 383 | + } 384 | +#endif 385 | if (svr_opts.forced_command) { 386 | dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command); 387 | } 388 | -------------------------------------------------------------------------------- /extension/extensions/usbnetlite/bin/usbnetlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # KUAL USBNetwork actions helper script 4 | # 5 | # $Id: usbnet.sh 19280 2023-10-30 23:59:04Z NiLuJe $ 6 | # 7 | ## 8 | 9 | # Get hackname from the script's path (NOTE: Will only work for scripts called from /mnt/us/extensions/${KH_HACKNAME}) 10 | # KH_HACKNAME="${PWD##/mnt/us/extensions/}" 11 | # fuck that 12 | KH_HACKNAME="usbnetlite" 13 | 14 | # Try to pull our custom helper lib 15 | libkh_fail="false" 16 | # Handle both the K5 & legacy helper, so I don't have to maintain the exact same thing in two different places :P 17 | for my_libkh in libkh5 libkh ; do 18 | _KH_FUNCS="/mnt/us/${KH_HACKNAME}/bin/${my_libkh}" 19 | if [ -f ${_KH_FUNCS} ] ; then 20 | . ${_KH_FUNCS} 21 | # Got it, go away! 22 | libkh_fail="false" 23 | break 24 | else 25 | libkh_fail="true" 26 | fi 27 | done 28 | 29 | if [ "${libkh_fail}" == "true" ] ; then 30 | # Pull default helper functions for logging 31 | _FUNCTIONS=/etc/rc.d/functions 32 | [ -f ${_FUNCTIONS} ] && . ${_FUNCTIONS} 33 | # We couldn't get our custom lib, abort 34 | msg "couldn't source libkh5 nor libkh from '${KH_HACKNAME}'" W 35 | exit 0 36 | fi 37 | 38 | # We need the proper privileges... 39 | if [ "$(id -u)" -ne 0 ] ; then 40 | kh_msg "unprivileged user, aborting" E v 41 | exit 1 42 | fi 43 | 44 | ## Enable a specific trigger file in the hack's basedir 45 | # Arg 1 is exact config trigger file name 46 | ## 47 | enable_hack_trigger_file() 48 | { 49 | if [ $# -lt 1 ] ; then 50 | kh_msg "not enough arguments passed to enable_hack_trigger_file ($# while we need at least 1)" W v "missing trigger file name" 51 | fi 52 | 53 | kh_trigger_file="${KH_HACK_BASEDIR}/${1}" 54 | 55 | touch "${kh_trigger_file}" 56 | } 57 | 58 | ## Remove a specific trigger file in the hack's basedir 59 | # Arg 1 is exact config trigger file name 60 | ## 61 | disable_hack_trigger_file() 62 | { 63 | if [ $# -lt 1 ] ; then 64 | kh_msg "not enough arguments passed to disable_hack_trigger_file ($# while we need at least 1)" W v "missing trigger file name" 65 | return 1 66 | fi 67 | 68 | kh_trigger_file="${KH_HACK_BASEDIR}/${1}" 69 | 70 | rm -f "${kh_trigger_file}" 71 | } 72 | 73 | ## Check if we're in USBMS mode 74 | check_is_in_usbnet() 75 | { 76 | if lsmod | grep -q g_ether ; then 77 | kh_msg "will not edit usbnet config file in usbnet mode, switch to usbms" W v "must be in usbms mode to safely do this" 78 | return 0 79 | fi 80 | 81 | # Avoid touching the config while SSHD is up in wifi only mode, too 82 | if [ "${USE_WIFI_SSHD_ONLY}" == "true" ] ; then 83 | if [ -f "${SSH_PID}" ] ; then 84 | kh_msg "will not edit usbnet config file while sshd is up, shut it down" W v "sshd must be down to safely do this" 85 | return 0 86 | fi 87 | fi 88 | 89 | # All good, we're in USBMS mode 90 | return 1 91 | } 92 | 93 | ## Check the current USBNET status (in more details than check_is_in_usbnet ;) 94 | check_usbnet_status() 95 | { 96 | # Source the config to get the wifi only current status 97 | . "${KH_HACK_BASEDIR}/etc/config" 98 | 99 | if [ "${USE_WIFI_SSHD_ONLY}" == "true" ] ; then 100 | # Don't do anything fancier (like checking if the pid still exists), because the actual usbnetwork script doesnt ;). 101 | if [ -f "${SSH_PID}" ] ; then 102 | kh_msg "wifi only, sshd should be up" I q 103 | return 3 104 | else 105 | kh_msg "wifi only, sshd should be down" I q 106 | return 4 107 | fi 108 | else 109 | # We're not in wifi only mode, do it like check_is_in_usbnet 110 | if lsmod | grep -q g_ether ; then 111 | if [ -f "${SSH_PID}" ] ; then 112 | kh_msg "currently in usbnet mode, sshd should be up" I q 113 | return 5 114 | else 115 | kh_msg "currently in usbnet mode, but sshd appears to be down!" I q 116 | return 6 117 | fi 118 | else 119 | if [ -f "${SSH_PID}" ] ; then 120 | kh_msg "currently in usbms mode, but sshd appears to be up!" I q 121 | return 7 122 | else 123 | kh_msg "currently in usbms mode, sshd should be down" I q 124 | return 8 125 | fi 126 | fi 127 | fi 128 | 129 | # Huh. Unknown state, shouldn't happen. 130 | return 1 131 | } 132 | 133 | ## Check if we're plugged in to something 134 | check_is_plugged_in() 135 | { 136 | # NOTE: On the KOA2, this is safe. It's so safe that it even helps avoid a kernel crash :D. 137 | # Jokes aside, yes, see the relevant comments in usbnet_to_usbms @ usbnet/bin/usbnetwork 138 | # NOTE: Assume the KOA3 behaves the same, even if there's a chance the kernel has since been fixed... 139 | [ "${IS_KOA2}" == "true" -o "${IS_KOA3}" == "true" ] && return 1 140 | 141 | # Try to check if we're plugged in... 142 | is_plugged_in="false" 143 | # There's no kdb in FW 2.x... 144 | if [ -d "/etc/kdb" ] ; then 145 | # The file might not exist when unplugged, silence stderr to avoid flooding KUAL's log. 146 | if [ "$(cat $(kdb get system/driver/usb/SYS_CONNECTED) 2>/dev/null)" == "1" ] ; then 147 | is_plugged_in="true" 148 | fi 149 | else 150 | # NOTE: Seems to be more useful than lipc-get-prop -i -e -- com.lab126.powerd isCharging (accurate in USBMS mode)... 151 | # On the other hand, /sys/devices/platform/arc_udc/connected doesn't seem to be very useful... 152 | if [ "$(cat /sys/devices/platform/charger/charging 2>/dev/null)" == "1" ] ; then 153 | is_plugged_in="true" 154 | fi 155 | fi 156 | if [ "${is_plugged_in}" == "true" ] ; then 157 | kh_msg "will not toggle usbnet while plugged in, unplug your kindle" W v "must not be plugged in to safely do that" 158 | return 0 159 | fi 160 | 161 | # All good, (apparently) not plugged in to anything 162 | return 1 163 | } 164 | 165 | ## Check if we're a WiFi device (!= K1/K2/DX/DXG) 166 | check_is_wifi_device() 167 | { 168 | [ "${IS_K1}" == "true" ] && return 1 169 | # DX & DXG are folded in IS_K2 170 | [ "${IS_K2}" == "true" ] && return 1 171 | 172 | # We are, all good :) 173 | return 0 174 | } 175 | 176 | ## Check if we're a legacy device (< K4) 177 | check_is_legacy_device() 178 | { 179 | [ "${IS_K1}" == "true" ] && return 0 180 | [ "${IS_K2}" == "true" ] && return 0 181 | [ "${IS_K3}" == "true" ] && return 0 182 | 183 | # We're not, all good :) 184 | return 1 185 | } 186 | 187 | ## Check if we're a Touch device (>= K5) 188 | check_is_touch_device() 189 | { 190 | [ "${IS_K5}" == "true" ] && return 0 191 | [ "${IS_TOUCH}" == "true" ] && return 0 192 | [ "${IS_PW}" == "true" ] && return 0 193 | [ "${IS_PW2}" == "true" ] && return 0 194 | [ "${IS_KV}" == "true" ] && return 0 195 | [ "${IS_KT2}" == "true" ] && return 0 196 | [ "${IS_PW3}" == "true" ] && return 0 197 | [ "${IS_KOA}" == "true" ] && return 0 198 | [ "${IS_KT3}" == "true" ] && return 0 199 | [ "${IS_KOA2}" == "true" ] && return 0 200 | [ "${IS_PW4}" == "true" ] && return 0 201 | [ "${IS_KT4}" == "true" ] && return 0 202 | [ "${IS_KOA3}" == "true" ] && return 0 203 | [ "${IS_PW5}" == "true" ] && return 0 204 | [ "${IS_KT5}" == "true" ] && return 0 205 | [ "${IS_KS}" == "true" ] && return 0 206 | 207 | # We're not, all good :) 208 | return 1 209 | } 210 | 211 | ## Toggle a specific config switch in the hack's config 212 | # Arg 1 is the exact name of the config switch (var name) 213 | # Arg 2 is the value of the switch (true || false) 214 | ## 215 | edit_hack_config() 216 | { 217 | if [ $# -lt 2 ] ; then 218 | kh_msg "not enough arguments passed to disable_hack_trigger_file ($# while we need at least 2)" W v "missing config switch and value" 219 | return 1 220 | fi 221 | 222 | # We do NOT want to edit the config file if we're not in USBMS mode, to avoid leaving the hack in an undefined state 223 | if check_is_in_usbnet ; then 224 | return 1 225 | fi 226 | 227 | kh_config_file="${KH_HACK_BASEDIR}/etc/config" 228 | 229 | kh_config_switch_name="${1}" 230 | kh_config_switch_value="${2}" 231 | # Sanitize user input 232 | if ! grep -q "${kh_config_switch_name}" "${kh_config_file}" ; then 233 | kh_msg "invalid config switch name (${kh_config_switch_name})" W v "invalid config switch" 234 | return 1 235 | fi 236 | 237 | # This is slightly overkill, the hack already discards the value if it's not true or false in lowercase... 238 | case "$kh_config_switch_value" in 239 | t* | y* | T* | Y* | 1 ) 240 | kh_config_switch_value="true" 241 | ;; 242 | f* | n* | F* | N* | 0 ) 243 | kh_config_switch_value="false" 244 | ;; 245 | * ) 246 | kh_msg "invalid config switch value (${kh_config_switch_value})" W v "invalid config value" 247 | return 1 248 | ;; 249 | esac 250 | 251 | # Do the deed... 252 | sed -r -e "s/^(${kh_config_switch_name})(=)([\"'])(.*?)([\"'])$/\1\2\3${kh_config_switch_value}\5/" -i "${kh_config_file}" 253 | } 254 | 255 | ## Try to toggle USBNetwork 256 | toggle_usbnet() 257 | { 258 | # All kinds of weird stuff happens if we try to toggle USBNet while plugged in, so, well, don't do it ;) 259 | if check_is_plugged_in ; then 260 | return 1 261 | fi 262 | 263 | kh_msg "Toggle USBNetwork" I a 264 | ${KH_HACK_BINDIR}/usbnetwork 265 | # NOTE: Send a blank kh_msg to avoid confusing users in verbose mode? That seem counterproductive... 266 | } 267 | 268 | ## Print the current USBnetwork mode 269 | usbnet_status() 270 | { 271 | # Check... 272 | check_usbnet_status 273 | usbnet_status="$?" 274 | 275 | # Interpret it 276 | case "${usbnet_status}" in 277 | 3 ) 278 | kh_msg "* SSHD is up (usbms, wifi only) *" I v 279 | ;; 280 | 4 ) 281 | kh_msg "* SSHD is down (usbms, wifi only) *" I v 282 | ;; 283 | 5 ) 284 | kh_msg "* USBNetwork: enabled (usbnet, sshd up) *" I v 285 | ;; 286 | 6 ) 287 | kh_msg "* USBNetwork: enabled (usbnet, sshd down?) *" I v 288 | ;; 289 | 7 ) 290 | kh_msg "* USBNetwork: disabled (usbms, sshd up?) *" I v 291 | ;; 292 | 8 ) 293 | kh_msg "* USBNetwork: disabled (usbms, sshd down) *" I v 294 | ;; 295 | * ) 296 | # Hu oh... 297 | kh_msg "* USBNetwork is broken? *" I v 298 | ;; 299 | esac 300 | } 301 | 302 | ## Enable SSH at boot 303 | enable_auto() 304 | { 305 | enable_hack_trigger_file "auto" 306 | # FIXME: Workaround broken? custom status message by using eips ourselves. Kill this once it works properly. 307 | kh_msg "Boot the Kindle in USBNet mode" I a 308 | # On legacy devices, prevent the device from shutting down when hitting the 'YKNR' screen, it might come in handy. 309 | # NOTE: On newer devices, we have RP+CRP instead ;). 310 | if ! check_is_touch_device ; then 311 | touch /mnt/us/DONT_HALT_ON_REPAIR 312 | fi 313 | } 314 | 315 | ## Disable SSH at boot 316 | disable_auto() 317 | { 318 | disable_hack_trigger_file "auto" 319 | kh_msg "Boot the Kindle in USBMS mode" I a 320 | } 321 | 322 | ## Enable verbose mode 323 | enable_verbose() 324 | { 325 | enable_hack_trigger_file "verbose" 326 | kh_msg "Make USBNetwork verbose" I a 327 | } 328 | 329 | ## Disable verbose mode 330 | disable_verbose() 331 | { 332 | disable_hack_trigger_file "verbose" 333 | kh_msg "Make USBNetwork quiet" I a 334 | } 335 | 336 | ## Enable complete uninstall flag 337 | enable_uninstall() 338 | { 339 | enable_hack_trigger_file "uninstall" 340 | kh_msg "Flag USBNetwork for complete uninstall" I a 341 | } 342 | 343 | ## Disable complete uninstall flag 344 | disable_uninstall() 345 | { 346 | disable_hack_trigger_file "uninstall" 347 | kh_msg "Restore default USBNetwork uninstall behavior" I a 348 | } 349 | 350 | ## Enable SSH over WiFi 351 | enable_wifi() 352 | { 353 | # NOTE: Extra safety, this is nonsensical on devices without a WiFi chip ;). 354 | if ! check_is_wifi_device ; then 355 | kh_msg "Not applicable to your device" W v 356 | return 1 357 | fi 358 | 359 | # Put the kh_msg before the edit, to be able to see the warnings in case of error 360 | kh_msg "Enable SSH over WiFi" I a 361 | 362 | # In my infinite wisdom, I changed the variable name in the K5 version... 363 | if check_is_touch_device ; then 364 | edit_hack_config "USE_WIFI" "true" 365 | else 366 | edit_hack_config "K3_WIFI" "true" 367 | fi 368 | } 369 | 370 | ## Disable SSH over WiFi 371 | disable_wifi() 372 | { 373 | if ! check_is_wifi_device ; then 374 | kh_msg "Not applicable to your device" W v 375 | return 1 376 | fi 377 | 378 | kh_msg "Disable SSH over WiFi" I a 379 | 380 | if check_is_touch_device ; then 381 | edit_hack_config "USE_WIFI" "false" 382 | else 383 | edit_hack_config "K3_WIFI" "false" 384 | fi 385 | } 386 | 387 | ## Enable SSHD only mode 388 | enable_sshd_only() 389 | { 390 | if ! check_is_wifi_device ; then 391 | kh_msg "Not applicable to your device" W v 392 | return 1 393 | fi 394 | 395 | kh_msg "Enable SSHD only over WiFi" I a 396 | 397 | if check_is_touch_device ; then 398 | edit_hack_config "USE_WIFI_SSHD_ONLY" "true" 399 | else 400 | edit_hack_config "K3_WIFI_SSHD_ONLY" "true" 401 | fi 402 | } 403 | 404 | ## Disable SSHD only mode 405 | disable_sshd_only() 406 | { 407 | if ! check_is_wifi_device ; then 408 | kh_msg "Not applicable to your device" W v 409 | return 1 410 | fi 411 | 412 | kh_msg "Disable SSHD only over WiFi" I a 413 | 414 | if check_is_touch_device ; then 415 | edit_hack_config "USE_WIFI_SSHD_ONLY" "false" 416 | else 417 | edit_hack_config "K3_WIFI_SSHD_ONLY" "false" 418 | fi 419 | } 420 | 421 | ## Move to OpenSSH 422 | use_openssh() 423 | { 424 | kh_msg "Switch to OpenSSH" I a 425 | edit_hack_config "USE_OPENSSH" "true" 426 | } 427 | 428 | ## Move back to Dropbear 429 | use_dropbear() 430 | { 431 | kh_msg "Switch to DropBear" I a 432 | edit_hack_config "USE_OPENSSH" "false" 433 | } 434 | 435 | ## Make dropbear quieter 436 | quiet_dropbear() 437 | { 438 | kh_msg "Don't let dropbear print the banner file" I a "Make dropbear quieter" 439 | edit_hack_config "QUIET_DROPBEAR" "true" 440 | } 441 | 442 | ## Let dropbear print the banner 443 | verbose_dropbear() 444 | { 445 | kh_msg "Let dropbear print the banner file" I a 446 | edit_hack_config "QUIET_DROPBEAR" "false" 447 | } 448 | 449 | ## Unique MAC addresses 450 | tweak_mac() 451 | { 452 | kh_msg "Use unique MAC addresses" I a 453 | edit_hack_config "TWEAK_MAC_ADDRESS" "true" 454 | } 455 | 456 | ## Default MAC addresses 457 | default_mac() 458 | { 459 | kh_msg "Use default MAC addresses" I a 460 | edit_hack_config "TWEAK_MAC_ADDRESS" "false" 461 | } 462 | 463 | ## Let volumd do the low-level heavy-lifting (default on K4, K5 & PW) 464 | use_volumd() 465 | { 466 | # NOTE: Extra safety, we *really* don't want to run this on anything other than a K2/3 467 | if ! check_is_legacy_device ; then 468 | kh_msg "Not supported on your device" W v 469 | return 1 470 | fi 471 | 472 | kh_msg "Use volumd" I a 473 | edit_hack_config "USE_VOLUMD" "true" 474 | } 475 | 476 | ## Do the kernel module switch & if up ourselves (default on legacy devices) 477 | dont_use_volumd() 478 | { 479 | if ! check_is_legacy_device ; then 480 | kh_msg "Not supported on your device" W v 481 | return 1 482 | fi 483 | 484 | kh_msg "Do not use volumd" I a 485 | edit_hack_config "USE_VOLUMD" "false" 486 | } 487 | 488 | ## Restore the default config file 489 | restore_config() 490 | { 491 | # Don't touch the config if we're in usbnet mode... 492 | if check_is_in_usbnet ; then 493 | return 1 494 | fi 495 | 496 | if [ -f "${USBNET_BASEDIR}/etc/config.default" ] ; then 497 | kh_msg "Restore default config file" I a 498 | cp -f "${USBNET_BASEDIR}/etc/config.default" "${USBNET_BASEDIR}/etc/config" 499 | else 500 | kh_msg "No default config file" W v 501 | fi 502 | } 503 | 504 | ## Print the version of the hack currently installed 505 | show_version() 506 | { 507 | if [ -f "${KH_HACK_BASEDIR}/etc/VERSION" ] ; then 508 | kh_msg "$(cat ${KH_HACK_BASEDIR}/etc/VERSION)" I v 509 | else 510 | kh_msg "No version info file" W v 511 | fi 512 | } 513 | 514 | ## Main 515 | case "${1}" in 516 | "toggle_usbnet" ) 517 | ${1} 518 | ;; 519 | "usbnet_status" ) 520 | ${1} 521 | ;; 522 | "enable_auto" ) 523 | ${1} 524 | ;; 525 | "disable_auto" ) 526 | ${1} 527 | ;; 528 | "enable_wifi" ) 529 | ${1} 530 | ;; 531 | "disable_wifi" ) 532 | ${1} 533 | ;; 534 | "restore_config" ) 535 | ${1} 536 | ;; 537 | "show_version" ) 538 | ${1} 539 | ;; 540 | * ) 541 | kh_msg "invalid action (${1})" W v "invalid action" 542 | ;; 543 | esac 544 | -------------------------------------------------------------------------------- /extension/usbnetlite/bin/usbnetwork: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Toggle from USB mass storage to USB network 4 | # 5 | # $Id: usbnetwork 16254 2019-07-23 21:58:00Z NiLuJe $ 6 | # 7 | ## 8 | 9 | # Hardcode hackname for usbnet, because we can be called from /test/bin when invoked by the private command usbNetwork 10 | KH_HACKNAME="usbnetlite" 11 | 12 | # Try to pull our custom helper lib 13 | _KH_FUNCS="/mnt/us/${KH_HACKNAME}/bin/libkh5" 14 | if [ -f ${_KH_FUNCS} ] ; then 15 | . ${_KH_FUNCS} 16 | else 17 | # Pull default helper functions for logging 18 | _FUNCTIONS=/etc/upstart/functions 19 | [ -f ${_FUNCTIONS} ] && . ${_FUNCTIONS} 20 | # We couldn't get our custom lib, abort 21 | f_log W usbnet script "" "couldn't source libkh5 from '${KH_HACKNAME}'" 22 | exit 0 23 | fi 24 | 25 | # We need the proper privileges (especially when called from the search bar)... 26 | if [ "$(id -u)" -ne 0 ] ; then 27 | kh_msg "unprivileged user, aborting" E v 28 | exit 1 29 | fi 30 | 31 | # FIXME: That's probably not needed anymore on the K5 32 | if [ "$1" == "status" ] ; then 33 | kh_msg "we're not using usbnetd, go away" I q 34 | 35 | # Yeah, actually, we need to return !0, that's the whole point... 36 | exit 1 37 | fi 38 | 39 | # FIXME: FW 5.9.x is showing hints of a potentially impending switch to the new USB gadgets (u_ether instead of g_ether). 40 | # This would need handling here and in the install script. 41 | # Here, we'd need to swap a variable between g_ether and u_ether based on a K5_ATLEAST_59 or IS_KOA2 check, 42 | # (based on whether the PW3 on FW 5.9 falls under the same predicament or not), 43 | # and in the install script, same deal, with the additional need to check if the kernel module parameters have changed or not... 44 | # Alternatively, we might be able to get the name of the right module out of a few specific keys in the elektra db. 45 | 46 | # Load config... 47 | if [ -f "${USBNETLITE_IFCONFIG}" ] ; then 48 | # dos2unix... 49 | sed -e "s/$(echo -ne '\r')$//g" -i ${USBNETLITE_IFCONFIG} 50 | . ${USBNETLITE_IFCONFIG} 51 | else 52 | kh_msg "!! your usbnet config is missing, we'll use the default values" W a "missing usbnet config" 53 | fi 54 | 55 | # Sanitize our user input, in case something stupid happened to the config file (like Windows...) 56 | # NOTE: This is obviously the fallback to default config values. Don't edit me here, that won't do a thing. 57 | # The live config is located in usbnet/etc/config 58 | if [ -z "${KINDLE_IP}" ] ; then 59 | KINDLE_IP=192.168.15.244 60 | kh_msg "!! your usbnet config is broken, restoring KINDLE_IP to default value" W a "broken usbnet config for KINDLE_IP" 61 | fi 62 | # Be very strict here, we only accept "true" and "false", everything else will be considered "false"! 63 | if [ "${USE_WIFI}" != "true" ] ; then 64 | # Don't throw a fuss if we deliberately set this to "false" 65 | if [ "${USE_WIFI}" != "false" ] ; then 66 | USE_WIFI="false" 67 | kh_msg "!! your usbnet config is broken, restoring USE_WIFI to default value" W a "broken usbnet config for USE_WIFI" 68 | fi 69 | fi 70 | if [ "${PASSWORD_OVERRIDE_ENABLED}" != "true" ] ; then 71 | if [ "${PASSWORD_OVERRIDE_ENABLED}" != "false" ] ; then 72 | PASSWORD_OVERRIDE_ENABLED="true" 73 | kh_msg "!! your usbnet config is broken, restoring PASSWORD_OVERRIDE_ENABLED to default value" W a "broken usbnet config for PASSWORD_OVERRIDE_ENABLED" 74 | fi 75 | fi 76 | if [ -z "${PASSWORD}" ] ; then 77 | PASSWORD="kindle" 78 | kh_msg "!! your usbnet config is broken restoring PASSWORD to default value" W a "broken usbnet config for PASSWORD" 79 | fi 80 | if [ "${ALLOW_PASSWORD_LOGIN}" != "true" ] ; then 81 | if [ "${ALLOW_PASSWORD_LOGIN}" != "false" ] ; then 82 | ALLOW_PASSWORD_LOGIN="true" 83 | kh_msg "!! your usbnet config is broken, restoring ALLOW_PASSWORD_LOGIN to default value" W a "broken usbnet config for ALLOW_PASSWORD_LOGIN" 84 | fi 85 | fi 86 | if [ -z "${PORT}" ] ; then 87 | PORT="22" 88 | kh_msg "!! your usbnet config is broken restoring PORT to default value" W a "broken usbnet config for PORT" 89 | fi 90 | 91 | 92 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -R" # Auto gen keys 93 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -H /mnt/us" # set the homedir to the userstore 94 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -p ${PORT}" # and bind to the specified port 95 | 96 | 97 | # only bind to usb0 if we're not using WiFi 98 | if [ "${USE_WIFI}" == "false" ] ; then 99 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -l usb0" 100 | fi 101 | # check if password login is disabled 102 | if [ "${ALLOW_PASSWORD_LOGIN}" == "false" ] ; then 103 | #disable password login 104 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -s" 105 | # if it isnt check if we have a master password 106 | elif [ "${PASSWORD_OVERRIDE_ENABLED}" == "true" ] ; then 107 | # Set the master password 108 | SSH_DAEMON_OPTS="${SSH_DAEMON_OPTS} -Y ${PASSWORD}" 109 | fi 110 | 111 | # USB NET => USB MS 112 | usbnet_to_usbms() { 113 | kh_msg "switching from usbnet to usbms" I 114 | # Do we only have an SSHD to kill? 115 | # FIXME: The KOA2 appears to be very finicky... In a number of circumstances, switching back to USBMS 116 | # *after* having used an USBNet connection goes horribly wrong (as in, kernel panic or deadlock). 117 | # We've tried a few things (like doing without the fake-ish hal events), with or without being plugged in 118 | # at the time, and the only thing that apears to not always go terribly wrong is: 119 | # Doing it just as usual (volumd, hal, hal) but *only when being plugged in*! 120 | # So, to *try* to avoid most, if not all, of the potential for crashes, without admitting utter defeat 121 | # and simply recommending a reboot, abort if the device is unplugged, and document that quirk. 122 | # NOTE: This obviously throws a wrench in our nice teardown of the telnetd/sshd daemons, since the switch 123 | # to USBMS becomes immediate after the usbUnconfigured event, and our daemons *live* in the userstore... 124 | # But, oh, well, c'est la vie... 125 | # NOTE: Assume the KOA3 still behaves the same way, although this ought to be reviewed, 126 | # as there's a chance the kernel has been fixed... 127 | if [ "${IS_KOA2}" == "true" -o "${IS_KOA3}" == "true" ] ; then 128 | # NOTE: The file may disappear when unplugged, so, test for != 1 instead of == 0 to cover every possibilities ;). 129 | # (Since cat'ing a non-existent file will return nothing, and not 0). 130 | if [ "$(cat $(kdb get system/driver/usb/SYS_CONNECTED) 2>/dev/null)" != "1" ] ; then 131 | kh_msg "will *only* switch to usbms while plugged in, plug your kindle back in" W v "must be plugged in to safely do that" 132 | kh_msg "this is a KOA2 & KOA3 specific workaround to avoid all manners of weird crashes :(" I q 133 | # And GTFO, and hope nothing will blow up when the user next plugs the device... ;). 134 | exit 0 135 | fi 136 | fi 137 | 138 | # Stop USB Network IF 139 | kh_msg "bringing usb0 interface down" I q 140 | ifconfig usb0 down || exit 0 141 | 142 | # Ask volumd to unload the ethernet gadget and load the mass storage one 143 | kh_msg "setting volumd useUsbForNetwork 0" I q 144 | lipc-set-prop -i -- com.lab126.volumd useUsbForNetwork 0 145 | 146 | # Let stuff settle for a while . . . 147 | sleep 1 148 | # NOTE: We appear to, at least on some device/FW combos, 149 | # need an usbPlugOut event for volumd to actually proceed in operating the switch... 150 | # But if we're already unplugged, that doesn't do the job, 151 | # and instead, we need to send an usbUnconfigured event... 152 | # Do both to make everyone happy. 153 | kh_msg "sending an usbUnconfigured event" I q 154 | lipc-send-event -r 3 -d 2 com.lab126.hal usbUnconfigured 155 | # Let stuff settle for a while, leaving some time for the USB stack to do its thing . . . 156 | sleep 2 157 | # NOTE: And just to be on the safe side, send a potentially extraneous unplug event ;). 158 | kh_msg "sending an usbPlugOut event" I q 159 | lipc-send-event -r 3 -d 2 com.lab126.hal usbPlugOut 160 | # Let stuff settle for a while, leaving some time for the USB stack to do its thing . . . 161 | sleep 2 162 | 163 | # Double-check that volumd successfully handled the switch... 164 | local max_volumd_wait=3 165 | local wait_iter=1 166 | # Check a few times... 167 | while lsmod | grep -q g_ether ; do 168 | # Don't wait more than 6 secs... 169 | let "wait_iter+=1" 170 | if [ ${wait_iter} -gt ${max_volumd_wait} ] ; then 171 | kh_msg "failed to disable usbnet" E v 172 | # NOTE: Check if we're still plugged in, because that may have had an averse effect (or not). 173 | if [ "$(cat $(kdb get system/driver/usb/SYS_CONNECTED) 2>/dev/null)" == "1" ] ; then 174 | # NOTE: Usually, a plugout event jog things up, so, that should end up being a half-decent advice... 175 | kh_msg "try to unplug the device" W v 176 | else 177 | # NOTE: Same idea, but since we're already unplugged, recommend a full plug/unplug cycle. 178 | # If you're starting to hear The IT Crowd's theme music in the background, join the club! 179 | kh_msg "try to plug & unplug the device" W v 180 | fi 181 | # Sleep for a while so people have time to read that... 182 | sleep 5 183 | # NOTE: By then, the usb0 interface is down, so we can't get back in... 184 | # We could try re-upping the if and re-setting useUsbForNetwork to 1, 185 | # but that'll probably lead to insanity... 186 | # NOTE: So instead, we do *not* exit, we break out of the loop, and carry on bringing the daemons down. 187 | # At least you'll only need one manual plugin/plugout cycle to jog volumd into action... 188 | break 189 | fi 190 | 191 | # Try again in a while... 192 | kh_msg "volumd hasn't quite yet disabled usbnet mode" I q 193 | sleep 2 194 | done 195 | 196 | # Stop ssh daemons 197 | 198 | 199 | kh_msg "stopping sshd" I 200 | /sbin/start-stop-daemon -q -p ${SSH_PID} -x ${SSH_DAEMON} -K 201 | if [ $? -ne 0 ] ; then 202 | kh_msg "failed to stop sshd" E 203 | fi 204 | 205 | # Restore iptables config 206 | if [ "${USE_WIFI}" == "true" ] ; then 207 | kh_msg "restoring iptables config" I 208 | iptables -D INPUT -i wlan0 -p tcp --dport ${PORT} -j ACCEPT 209 | fi 210 | } 211 | 212 | # USB MS => USB NET 213 | usbms_to_usbnet() { 214 | kh_msg "switching from usbms to usbnet" I 215 | # Unload mass storage gadget and load ethernet one 216 | kh_msg "setting volumd useUsbForNetwork 1 . . ." I q 217 | # On the PW2, at boot, volumd might not have finished registering itself with dbus yet... 218 | local max_volumd_wait=10 219 | local wait_iter=1 220 | # So try to ask a few times... 221 | until lipc-set-prop -i -- com.lab126.volumd useUsbForNetwork 1 > /dev/null 2>&1 ; do 222 | # Don't wait more than 10 secs... 223 | let "wait_iter+=1" 224 | if [ ${wait_iter} -gt ${max_volumd_wait} ] ; then 225 | kh_msg "failed to communicate with volumd, giving up" E v 226 | # Sleep for a while so people have time to read that... 227 | sleep 5 228 | # And die in a shower a sparks! 229 | exit 0 230 | fi 231 | 232 | # Try again in a while... 233 | kh_msg "volumd isn't quite up yet" I q 234 | sleep 1 235 | done 236 | # Hold volumd's hand... 237 | # NOTE: This may or may not be strictly necessary, but if/when it isn't, it at least helps when switching modes 238 | # while being plugged in, something we *want* to support when switching *TO* USBNet, 239 | # because it can be useful to monitor the boot process when USBNet is enabled at boot ;). 240 | kh_msg "sending an usbUnconfigured event" I q 241 | lipc-send-event -r 3 -d 2 com.lab126.hal usbUnconfigured 242 | kh_msg "sending an usbPlugOut event" I q 243 | lipc-send-event -r 3 -d 2 com.lab126.hal usbPlugOut 244 | 245 | # We're relying on volumd, wait until the usb0 network interface comes up, to make sure we call ifconfig with our custom IP *after* volumd... 246 | kh_msg "waiting for volumd . . ." I q 247 | # Start with a decent amount of sleep to let the kernel do its thing... 248 | sleep 2 249 | 250 | # Reset the counter... 251 | wait_iter=1 252 | # Run our little C helper to see if usb0 is up... [NOTE: Can't remember what was wrong with /sys/class/net/usb0/operstate, /proc/net/arp, /proc/net/dev or /proc/net/dev_mcast anymore, but, hey, C, shiny! :D] 253 | # like hell im building a fancy c helper 254 | until [ -e /sys/class/net/usb0 ] ; do 255 | # Don't wait more than 10 secs... 256 | let "wait_iter+=1" 257 | if [ ${wait_iter} -gt ${max_volumd_wait} ] ; then 258 | kh_msg "usb0 is still not up, giving up" W q 259 | break 260 | fi 261 | 262 | # Try again in a while... 263 | kh_msg "usb0 is down" I q 264 | sleep 1 265 | done 266 | 267 | # Reconfigure USB Network IF (because volumd defaults to an IP that might be different from the one we want) 268 | kh_msg "reconfiguring usb0 interface" I q 269 | # NOTE: If we just ate the 15s loop on kindle_usbnet_addr because the Kindle was plugged in, this will most likely fail. 270 | ifconfig usb0 ${KINDLE_IP} 271 | if [ $? -ne 0 ] ; then 272 | # Warn the user that it failed... 273 | kh_msg "failed to set usb0 ip, this is bad" E v 274 | # Sleep for a while so people have time to read that... 275 | sleep 5 276 | fi 277 | 278 | # Start ssh daemon 279 | 280 | [ -x /usr/bin/dropbear ] || chmod +x /usr/bin/dropbear 281 | # If we're in SSHD only mode, we'll get here *every* usbNetwork call, since we never load g_ether. 282 | # So make sure we toggle SSHD start/stop instead 283 | if [ -f ${SSH_PID} ] ; then 284 | kh_msg "stopping sshd" I 285 | /sbin/start-stop-daemon -q -p ${SSH_PID} -x ${SSH_DAEMON} -K 286 | if [ $? -ne 0 ] ; then 287 | kh_msg "failed to stop sshd" E 288 | fi 289 | # Wait for a bit, to make sure start-stop-daemon did its job... 290 | sleep 2 291 | # Make some noise if we *still* have a pidfile (pid mismatch? stale pidfile? crashed/broken dropbear?) 292 | if [ -f ${SSH_PID} ] ; then 293 | # Check if it's alive, and ours 294 | pid=$( cat ${SSH_PID} ) 295 | # Kill stale pidfile 296 | kh_msg "removing stale sshd pidfile" W 297 | rm -f ${SSH_PID} 298 | # If we do indeed have one, then check that it's really dropbear or OpenSSH 299 | if ps -fp ${pid} | grep -q -e "dropbear" -e "sshd" ; then 300 | kh_msg "killing stale sshd (${pid})" W 301 | kill -TERM ${pid} 2> /dev/null 302 | else 303 | # It's not ours, so assume the pidfile is really stale, from a crash/hard-reboot, and that we want to *start* SSHD... 304 | kh_msg "starting sshd" I 305 | /sbin/start-stop-daemon -q -p ${SSH_PID} -x ${SSH_DAEMON} -S -- ${SSH_DAEMON_OPTS} 306 | if [ $? -ne 0 ] ; then 307 | kh_msg "failed to start sshd" E v 308 | fi 309 | fi 310 | else 311 | kh_msg "starting sshd" I 312 | /sbin/start-stop-daemon -q -p ${SSH_PID} -x ${SSH_DAEMON} -S -- ${SSH_DAEMON_OPTS} 313 | if [ $? -ne 0 ] ; then 314 | kh_msg "failed to start sshd" E v 315 | fi 316 | fi 317 | else 318 | kh_msg "starting sshd" I 319 | /sbin/start-stop-daemon -q -p ${SSH_PID} -x ${SSH_DAEMON} -S -- ${SSH_DAEMON_OPTS} 320 | if [ $? -ne 0 ] ; then 321 | kh_msg "failed to start sshd" E v 322 | fi 323 | fi 324 | 325 | # Allow SSH via WiFi 326 | if [ "${USE_WIFI}" == "true" ] ; then 327 | kh_msg "tweaking iptables config" I 328 | iptables -A INPUT -i wlan0 -p tcp --dport ${PORT} -j ACCEPT 329 | fi 330 | } 331 | 332 | # Go back to USB MS on stop, in order to fix the 'nothing exported over usbms' issue after an update 333 | # (NOTE: Might not be really that useful anymore on FW 5.x, since the ota updater trigger a full restart when it finishes...) 334 | # That's because volumd, which is started before us, *needs* g_file_storage loaded, or it won't properly setup the USBMS export. 335 | # The cleanest way to make everyone happy is to just go back to USB MS before entering the update runlevel. 336 | if [ "$1" == "usbms" ] ; then 337 | # We only want to switch back to USB MS 338 | if lsmod | grep -q g_ether ; then 339 | # Send a broadcast to notify users who skipped reading the manual, because that's a BadThing(TM)... 340 | # Basically, don't boot/go through rc5 while plugged to a computer, if you don't want to risk volumd pulling crazy stunts. 341 | wall "We're switching back to USB MS, so if you're wondering why your terminal is frozen, go read the docs!" 342 | usbnet_to_usbms 343 | else 344 | kh_msg "usbnet is already stopped" I 345 | fi 346 | 347 | # Go away, we wouldn't want to re-toggle after that ;). 348 | return 0 349 | fi 350 | 351 | # Check if we're already in USB network mode, then return to USB Mass storage 352 | if lsmod | grep -q g_ether ; then 353 | usbnet_to_usbms 354 | else 355 | usbms_to_usbnet 356 | fi 357 | # FWIW, if we wanted to trust volumd/lipc: 358 | #if [ "$(lipc-get-prop -i -e -- com.lab126.volumd useUsbForNetwork)" == "1" ] ; then 359 | # usbnet_to_usbms 360 | #else 361 | # usbms_to_usbnet 362 | #fi 363 | 364 | exit 0 365 | -------------------------------------------------------------------------------- /extension/usbnetlite/bin/libkh5: -------------------------------------------------------------------------------- 1 | ## 2 | # 3 | # Custom logging code/constants for the hacks 4 | # 5 | # $Id: libkh5 19277 2023-10-30 23:34:16Z NiLuJe $ 6 | # 7 | # kate: syntax bash; 8 | # shellcheck shell=sh 9 | # 10 | ## 11 | 12 | # Pull some helper functions for logging 13 | _FUNCTIONS=/etc/upstart/functions 14 | [ -f ${_FUNCTIONS} ] && . ${_FUNCTIONS} 15 | 16 | ## Some constants 17 | LINKFONTS_BASEDIR="/mnt/us/linkfonts" 18 | LINKFONTS_CONFDIR="${LINKFONTS_BASEDIR}/etc" 19 | LINKFONTS_BINDIR="${LINKFONTS_BASEDIR}/bin" 20 | FONTCONFIG_HELPER="${LINKFONTS_BINDIR}/update-fontconfig" 21 | 22 | 23 | LINKSS_BASEDIR="/mnt/us/linkss" 24 | LINKSS_BINDIR="${LINKSS_BASEDIR}/bin" 25 | LINKSS_SHUFFLE="${LINKSS_BINDIR}/shuffless" 26 | LINKSS_COVER_EXTRACT="${LINKSS_BINDIR}/cover-extract" 27 | TOUCH_SCREEN_SIZE="600x800" 28 | PW_SCREEN_SIZE="758x1024" 29 | KV_SCREEN_SIZE="1072x1448" 30 | KOA2_SCREEN_SIZE="1264x1680" 31 | PW5_SCREEN_SIZE="1236x1648" 32 | KT5_SCREEN_SIZE="1072x1448" 33 | KS_SCREEN_SIZE="1860x2480" 34 | # And our actual screen size... We need to do a model check, because upstart/functions is not accurate on the PW (at least on 5.2.0)... 35 | # NOTE: An alternate way to do this would be to check the screen dpi via devcap: 36 | # [ "$(devcap-get-feature -i screen dpi)" == "212" ] && IS_PW="true" 37 | # Or, for now at least, the presence of a frontlight: 38 | # [ "$(devcap-get-feature -a frontlight)" == "1" ] && IS_PW="true" 39 | # We need the devcap daemon, though. AFAICT, it's up fairly early, so that should work, but, still ;). 40 | IS_TOUCH="false" 41 | IS_PW="false" 42 | IS_PW2="false" 43 | IS_KV="false" 44 | IS_KT2="false" 45 | IS_PW3="false" 46 | IS_KOA="false" 47 | IS_KT3="false" 48 | IS_KOA2="false" 49 | IS_PW4="false" 50 | IS_KT4="false" 51 | IS_KOA3="false" 52 | IS_PW5="false" 53 | IS_KT5="false" 54 | IS_KS="false" 55 | kmfc="$(cut -c1 /proc/usid)" 56 | if [ "${kmfc}" == "B" ] || [ "${kmfc}" == "9" ] ; then 57 | # Older device ID scheme 58 | kmodel="$(cut -c3-4 /proc/usid)" 59 | case "${kmodel}" in 60 | "24" | "1B" | "1D" | "1F" | "1C" | "20" ) 61 | # PaperWhite... 62 | IS_PW="true" 63 | ;; 64 | "D4" | "5A" | "D5" | "D6" | "D7" | "D8" | "F2" | "17" | "60" | "F4" | "F9" | "62" | "61" | "5F" ) 65 | # PaperWhite 2... 66 | IS_PW="true" 67 | IS_PW2="true" 68 | ;; 69 | "13" | "54" | "2A" | "4F" | "52" | "53" ) 70 | # Voyage... 71 | IS_KV="true" 72 | ;; 73 | "C6" | "DD" ) 74 | # KT2... 75 | IS_TOUCH="true" 76 | IS_KT2="true" 77 | ;; 78 | "0F" | "11" | "10" | "12" ) 79 | # Touch 80 | IS_TOUCH="true" 81 | ;; 82 | * ) 83 | # Fallback... We shouldn't ever hit that. 84 | IS_TOUCH="true" 85 | ;; 86 | esac 87 | else 88 | # Try the new device ID scheme... 89 | kmodel="$(cut -c4-6 /proc/usid)" 90 | case "${kmodel}" in 91 | "0G1" | "0G2" | "0G4" | "0G5" | "0G6" | "0G7" | "0KB" | "0KC" | "0KD" | "0KE" | "0KF" | "0KG" | "0LK" | "0LL" ) 92 | # PW3... 93 | IS_PW3="true" 94 | ;; 95 | "0GC" | "0GD" | "0GR" | "0GS" | "0GT" | "0GU" ) 96 | # Oasis... 97 | IS_KOA="true" 98 | ;; 99 | "0DU" | "0K9" | "0KA" ) 100 | # KT3... 101 | IS_KT3="true" 102 | ;; 103 | "0LM" | "0LN" | "0LP" | "0LQ" | "0P1" | "0P2" | "0P6" | "0P7" | "0P8" | "0S1" | "0S2" | "0S3" | "0S4" | "0S7" | "0SA" ) 104 | # KOA2... 105 | IS_KOA2="true" 106 | ;; 107 | "0PP" | "0T1" | "0T2" | "0T3" | "0T4" | "0T5" | "0T6" | "0T7" | "0TJ" | "0TK" | "0TL" | "0TM" | "0TN" | "102" | "103" | "16Q" | "16R" | "16S" | "16T" | "16U" | "16V" ) 108 | # PW4... 109 | IS_PW4="true" 110 | ;; 111 | "10L" | "0WF" | "0WG" | "0WH" | "0WJ" | "0VB" ) 112 | # KT4... 113 | IS_KT4="true" 114 | ;; 115 | "11L" | "0WQ" | "0WP" | "0WN" | "0WM" | "0WL" ) 116 | # KOA3... 117 | IS_KOA3="true" 118 | ;; 119 | "1LG" | "1Q0" | "1PX" | "1VD" | "219" | "21A" | "2BH" | "2BJ" | "2DK" ) 120 | # PW5... 121 | IS_PW5="true" 122 | ;; 123 | "22D" | "25T" | "23A" | "2AQ" | "2AP" | "1XH" | "22C" ) 124 | # KT5... 125 | IS_KT5="true" 126 | ;; 127 | "27J" | "2BL" | "263" | "227" | "2BM" | "23L" | "23M" | "270" ) 128 | # KS... 129 | IS_KS="true" 130 | ;; 131 | * ) 132 | # Fallback... We shouldn't ever hit that. 133 | IS_TOUCH="true" 134 | ;; 135 | esac 136 | fi 137 | # Now use the right constants for our model... 138 | if [ "${IS_KV}" == "true" -o "${IS_PW3}" == "true" -o "${IS_KOA}" == "true" -o "${IS_PW4}" == "true" ] ; then 139 | SCREEN_X_RES=1088 # NOTE: Yes, 1088, not 1072 or 1080... 140 | SCREEN_Y_RES=1448 141 | EIPS_X_RES=16 # Manually measured, should be accurate. 142 | EIPS_Y_RES=24 # Manually measured, should be accurate. 143 | MY_SCREEN_SIZE="${KV_SCREEN_SIZE}" 144 | elif [ "${IS_PW}" == "true" ] ; then 145 | SCREEN_X_RES=768 # NOTE: Yep, 768, not a typo... 146 | SCREEN_Y_RES=1024 147 | EIPS_X_RES=16 # Manually measured, should be accurate. 148 | EIPS_Y_RES=24 # Manually measured, should be accurate. 149 | MY_SCREEN_SIZE="${PW_SCREEN_SIZE}" 150 | elif [ "${IS_KT2}" == "true" -o "${IS_KT3}" == "true" -o "${IS_KT4}" == "true" ] ; then 151 | SCREEN_X_RES=608 152 | SCREEN_Y_RES=800 153 | EIPS_X_RES=16 # Manually measured, should be accurate. 154 | EIPS_Y_RES=24 # Manually measured, should be accurate. 155 | MY_SCREEN_SIZE="${TOUCH_SCREEN_SIZE}" 156 | elif [ "${IS_KOA2}" == "true" -o "${IS_KOA3}" == "true" ] ; then 157 | SCREEN_X_RES=1280 # NOTE: Yep, line_length/xres_virtual, not xres (1264) 158 | SCREEN_Y_RES=1680 159 | EIPS_X_RES=16 # Manually measured, should be accurate. 160 | EIPS_Y_RES=24 # Manually measured, should be accurate. 161 | MY_SCREEN_SIZE="${KOA2_SCREEN_SIZE}" 162 | elif [ "${IS_PW5}" == "true" ] ; then 163 | SCREEN_X_RES=1236 164 | SCREEN_Y_RES=1648 165 | EIPS_X_RES=16 # Manually measured, should be accurate. 166 | EIPS_Y_RES=24 # Manually measured, should be accurate. 167 | MY_SCREEN_SIZE="${PW5_SCREEN_SIZE}" 168 | elif [ "${IS_KT5}" == "true" ] ; then 169 | SCREEN_X_RES=1072 170 | SCREEN_Y_RES=1448 171 | EIPS_X_RES=16 # Manually measured, should be accurate. 172 | EIPS_Y_RES=24 # Manually measured, should be accurate. 173 | MY_SCREEN_SIZE="${KT5_SCREEN_SIZE}" 174 | elif [ "${IS_KS}" == "true" ] ; then 175 | SCREEN_X_RES=1860 176 | SCREEN_Y_RES=2480 177 | EIPS_X_RES=16 # Manually measured, should be accurate. 178 | EIPS_Y_RES=24 # Manually measured, should be accurate. 179 | MY_SCREEN_SIZE="${KS_SCREEN_SIZE}" 180 | else 181 | SCREEN_X_RES=600 # _v_width @ upstart/functions 182 | SCREEN_Y_RES=800 # _v_height @ upstart/functions 183 | EIPS_X_RES=12 # from f_puts @ upstart/functions 184 | EIPS_Y_RES=20 # from f_puts @ upstart/functions 185 | MY_SCREEN_SIZE="${TOUCH_SCREEN_SIZE}" 186 | fi 187 | EIPS_MAXCHARS="$((${SCREEN_X_RES} / ${EIPS_X_RES}))" 188 | EIPS_MAXLINES="$((${SCREEN_Y_RES} / ${EIPS_Y_RES}))" 189 | 190 | # USB watchdog lock file. It needs to be outside of the userstore, because vfat doesn't handle hardlinks, and we need hardlinks for atomic locking. 191 | USBWD_LOCK_DIR="/var/local/run" 192 | USBWD_LOCK_FILE="${USBWD_LOCK_DIR}/usbwd.lock" 193 | 194 | USBNET_BASEDIR="/mnt/us/usbnet" 195 | USBNET_BINDIR="${USBNET_BASEDIR}/bin" 196 | USBNET_IFCONFIG="${USBNET_BASEDIR}/etc/config" 197 | 198 | USBNETLITE_BASEDIR="/mnt/us/usbnetlite" 199 | USBNETLITE_BINDIR="${USBNETLITE_BASEDIR}/bin" 200 | USBNETLITE_IFCONFIG="${USBNETLITE_BASEDIR}/etc/config" 201 | 202 | SSH_DAEMON="/usr/bin/dropbear" 203 | REAL_SSH_DAEMON="/mnt/us/usbnetlite/bin/dropbearmulti" 204 | OPENSSH_DAEMON="/usr/sbin/sshd" 205 | REAL_OPENSSH_DAEMON="/mnt/us/usbnet/sbin/sshd" 206 | SSH_PID="${USBNETLITE_BASEDIR}/run/sshd.pid" 207 | SSH_DAEMON_OPTS="-P ${SSH_PID} -K 15" 208 | TELNET_DAEMON="${USBNET_BINDIR}/busybox" 209 | TELNET_DAEMON_OPTS="telnetd -F" 210 | TELNET_PID="${USBNET_BASEDIR}/run/telnetd.pid" 211 | 212 | 213 | ## And some more hack-specific constants 214 | KH_HACK_BASEDIR="/mnt/us/${KH_HACKNAME}" 215 | KH_HACK_BINDIR="${KH_HACK_BASEDIR}/bin" 216 | WATCHDOG_PID="${KH_HACK_BASEDIR}/run/usb-watchdog.pid" 217 | USBWD_REBOOT_FILE="${KH_HACK_BASEDIR}/reboot" 218 | WATCHDOG_DAEMON="${KH_HACK_BINDIR}/usb-watchdog" 219 | WATCHDOG_HELPER="${KH_HACK_BINDIR}/usb-watchdog-helper" 220 | USBWD_LOCK_BIN="${KH_HACK_BINDIR}/shlock" 221 | 222 | # tmpfs paths for ScreenSavers 223 | LINKSS_TMPFS_BASEDIR="/var/linkss" 224 | LINKSS_TMPFS_CACHE="${LINKSS_TMPFS_BASEDIR}/cache" 225 | LINKSS_TMPFS_COVERDIR="${LINKSS_TMPFS_BASEDIR}/cover" 226 | LINKSS_BASEDIR_BASE="/mnt/base-us/linkss" 227 | 228 | # varlocal paths for Fonts 229 | LINKFONTS_LOCAL_BASEDIR="/var/local/linkfonts" 230 | LINKFONTS_LOCAL_LIBDIR="${LINKFONTS_LOCAL_BASEDIR}/lib" 231 | 232 | # Cover watchdog for ScreenSavers 233 | COVERWD_LOCK_DIR="/var/local/run" 234 | COVERWD_LOCK_FILE="${COVERWD_LOCK_DIR}/coverwd.lock" 235 | COVER_WATCHDOG_PID="${KH_HACK_BASEDIR}/run/cover-watchdog.pid" 236 | COVER_WATCHDOG_DAEMON="${KH_HACK_BINDIR}/cover-watchdog" 237 | COVER_WATCHDOG_HELPER="${KH_HACK_BINDIR}/cover-watchdog-helper" 238 | COVERWD_LOCK_BIN="${KH_HACK_BINDIR}/shlock" 239 | 240 | # Python 241 | PYTHON_BASEDIR="/mnt/us/python" 242 | PYTHON_BINDIR="${PYTHON_BASEDIR}/bin" 243 | PYTHON="${PYTHON_BINDIR}/python2.7" 244 | 245 | 246 | # Check if arg is an int 247 | is_integer() 248 | { 249 | # Cheap trick ;) 250 | [ "${1}" -eq "${1}" ] 2>/dev/null 251 | return $? 252 | } 253 | 254 | ## Check if we have an FBInk binary available somewhere... 255 | # Default to something that won't horribly blow up... 256 | FBINK_BIN="true" 257 | for my_hackdir in linkss linkfonts libkh usbnet ; do 258 | my_fbink="/mnt/us/${my_hackdir}/bin/fbink" 259 | if [ -x "${my_fbink}" ] ; then 260 | FBINK_BIN="${my_fbink}" 261 | # Got it! 262 | break 263 | fi 264 | done 265 | kh_has_fbink() 266 | { 267 | # Because the fallback is the "true" binary/shell built-in ;). 268 | if [ "${FBINK_BIN}" != "true" ] ; then 269 | # Got it! 270 | return 0 271 | fi 272 | 273 | # If we got this far, we don't have fbink installed 274 | return 1 275 | } 276 | 277 | ## Print something on the bottom of the screen via FBInk 278 | # Arg 1 is the string to print 279 | fbink_prev_line_offset="0" 280 | kh_fbink_print() 281 | { 282 | # We need at least one arg 283 | if [ $# -lt 1 ] ; then 284 | f_log W ${KH_HACKNAME} libkh5 "" "not enough arguments passed to kh_fbink_print ($# while we need at least 1)" 285 | return 286 | fi 287 | 288 | kh_eips_string="${1}" 289 | 290 | # Unlike eips, we need at least a single space to even try to print something ;). 291 | if [ "${kh_eips_string}" == "" ] ; then 292 | kh_eips_string=" " 293 | fi 294 | 295 | # Support printing over 3 different lines before wrapping back to the baseline... 296 | fbink_row="$(( -4 + ${fbink_prev_line_offset} ))" 297 | # If we're printing on the baseline, blank the two extra lines, 298 | # plus the final line in case we had a previous multi-line print, 299 | # to potentially clear stale lines from another libkh instance... 300 | if [ ${fbink_row} -eq -4 ] ; then 301 | ${FBINK_BIN} -qpmL -y -3 " " " " " " 302 | fi 303 | # Handle the wraparound 304 | if [ ${fbink_row} -ge -1 ] ; then 305 | # Back to baseline! 306 | fbink_row="-4" 307 | fbink_prev_line_offset="0" 308 | # And strike the extra lines to make it clear we wrapped... 309 | ${FBINK_BIN} -qpmhL -y -3 " " " " " " 310 | fi 311 | 312 | # And just print it, FBInk will take care of the rest! 313 | # We just have to slurp the output to remember how many lines we just printed... 314 | fbink_line_count="$(${FBINK_BIN} -qpml -y ${fbink_row} "${kh_eips_string}")" 315 | # Sanity check just in case something goes horribly wrong... 316 | is_integer "${fbink_line_count}" || STEPCOUNT=0 317 | 318 | # And increment our offset... 319 | let "fbink_prev_line_offset+=fbink_line_count" 320 | } 321 | 322 | ## Print something on the bottom of the screen via eips 323 | # Arg 1 is the string to print 324 | kh_prev_line_offset="0" 325 | kh_eips_print() 326 | { 327 | # We need at least one arg 328 | if [ $# -lt 1 ] ; then 329 | f_log W ${KH_HACKNAME} libkh5 "" "not enough arguments passed to kh_eips_print ($# while we need at least 1)" 330 | return 331 | fi 332 | 333 | kh_eips_string="${1}" 334 | 335 | # If our string exceeds the column length, split it into as many lines as necessary... 336 | # Subtract the edge blocks, since, depending on the device, they might be half-hidden behind the bezel 337 | kh_maxlen="$(( ${EIPS_MAXCHARS} - 2 ))" 338 | kh_str_start="0" 339 | kh_line_offset="$(( ${#kh_eips_string} / ${kh_maxlen} ))" 340 | kh_full_eips_string="${kh_eips_string}" 341 | 342 | # Start by checking if we need to clear a previous multiline print... 343 | while [ ${kh_prev_line_offset} -ge 1 ] ; do 344 | # Build a blank line 345 | kh_str_line="" 346 | while [ ${#kh_str_line} -lt ${EIPS_MAXCHARS} ] ; do 347 | kh_str_line="${kh_str_line} " 348 | done 349 | 350 | # Print it 351 | eips 0 $((${EIPS_MAXLINES} - ( 2 + ${kh_prev_line_offset} ) )) "${kh_str_line}" >/dev/null 352 | # Switch to the next line 353 | let "kh_prev_line_offset-=1" 354 | done 355 | # And now remember the line offset for this print if it's multiline, so we can do that the next time... 356 | if [ ${#kh_eips_string} -gt ${kh_maxlen} ] ; then 357 | kh_prev_line_offset="${kh_line_offset}" 358 | else 359 | kh_prev_line_offset="0" 360 | fi 361 | 362 | # And now handle the line splitting... 363 | while [ ${#kh_eips_string} -gt ${kh_maxlen} ] ; do 364 | # Extract our current line 365 | kh_str_line="${kh_full_eips_string:${kh_str_start}:${kh_maxlen}}" 366 | # Update our start pointer 367 | kh_str_start="$(( ${kh_str_start} + ${kh_maxlen} ))" 368 | 369 | # Quick'n dirty hyphenation... 370 | # See if last char of line & first char of next line are both letters, 371 | # in which case do the right padding with an hyphen and not a space. 372 | kh_hyphen_test_str="${kh_full_eips_string:$(( ${kh_str_start} - 1 )):2}" 373 | # Use a dirty trick to use something that supports character classes, but doesn't fork ;). 374 | if [ -z "${kh_hyphen_test_str//[a-zA-Z]/}" ] ; then 375 | # We'll necessarily be the last char of the line, so we don't need to do any fancy checks on that front. 376 | kh_str_line="${kh_str_line}-" 377 | fi 378 | 379 | # Pad it... Left... 380 | kh_str_line=" ${kh_str_line}" 381 | # ... and Right 382 | while [ ${#kh_str_line} -lt ${EIPS_MAXCHARS} ] ; do 383 | kh_str_line="${kh_str_line} " 384 | done 385 | 386 | # Print it 387 | eips 0 $((${EIPS_MAXLINES} - ( 2 + ${kh_line_offset} ) )) "${kh_str_line}" >/dev/null 388 | # Switch to the next line 389 | let "kh_line_offset-=1" 390 | 391 | # Consume the base string to keep looping 392 | kh_eips_string="${kh_full_eips_string:${kh_str_start}}" 393 | done 394 | 395 | # Add a leading whitespace to avoid starting right at the left edge of the screen... 396 | kh_eips_string=" ${kh_eips_string}" 397 | 398 | # Since eips doesn't trigger a full refresh, we'll have to pad our string with blank spaces to make sure two consecutive messages don't run into each other. 399 | while [ ${#kh_eips_string} -lt ${EIPS_MAXCHARS} ] ; do 400 | kh_eips_string="${kh_eips_string} " 401 | done 402 | 403 | # And finally, show our formatted message on the bottom of the screen (NOTE: Redirect to /dev/null to kill unavailable character & pixel not in range warning messages) 404 | eips 0 $((${EIPS_MAXLINES} - 2)) "${kh_eips_string}" >/dev/null 405 | 406 | # NOTE: For some reason (probably relating to the state of the eInk controller), when eips is triggered during a reboot/shutdown/update runlevel (ie. when stopping stuff), 407 | # only the last message will be shown, and that only after a time (when the eInk controller changes state?), to the point that you might see the last message (usually usbnet) at the 408 | # beginning of the boot process when rebooting! 409 | } 410 | 411 | ## Custom logging 412 | # Arg 1 is logging message 413 | # Arg 2 is logging level 414 | # Arg 3 is eips/fbink logging status (quiet|verbose|auto) 415 | # Arg 4 is eips/fbink message 416 | ## 417 | kh_msg() 418 | { 419 | # We need at least two args 420 | if [ $# -lt 2 ] ; then 421 | f_log W ${KH_HACKNAME} libkh5 "" "not enough arguments passed to kh_msg ($# while we need at least 2)" 422 | return 423 | fi 424 | 425 | kh_msg_string="${1}" 426 | kh_loglvl="${2}" 427 | 428 | # Check if we want to trigger an additionnal eips print 429 | case "${3}" in 430 | "q" | "Q" ) 431 | kh_show_eips="false" 432 | ;; 433 | "v" | "V" ) 434 | kh_show_eips="true" 435 | ;; 436 | * ) 437 | # Only show if we find the verbose trigger file for this hack 438 | if [ -f "${KH_HACK_BASEDIR}/verbose" ] ; then 439 | kh_show_eips="true" 440 | else 441 | kh_show_eips="false" 442 | fi 443 | ;; 444 | esac 445 | 446 | # If we have a fourth argument, use it as a specific string to pass to eips, else use the same as f_log 447 | if [ -n "${4}" ] ; then 448 | kh_eips_string="${4}" 449 | else 450 | kh_eips_string="${kh_msg_string}" 451 | fi 452 | 453 | # Print to log 454 | f_log ${kh_loglvl} ${KH_HACKNAME} kh_msg "" "${kh_msg_string}" 455 | 456 | # Do we want to trigger an eips print? 457 | if [ "${kh_show_eips}" == "true" ] ; then 458 | # Detect from which hack we've been called, we'll use it to tag our message 459 | case "${KH_HACKNAME}" in 460 | "linkss" ) 461 | kh_eips_tag="S" 462 | ;; 463 | "linkfonts" ) 464 | kh_eips_tag="F" 465 | ;; 466 | "usbnet" ) 467 | kh_eips_tag="N" 468 | ;; 469 | "linkjail" ) 470 | kh_eips_tag="J" 471 | ;; 472 | * ) 473 | # Huh, shouldn't happen, but log it anyway. 474 | f_log W ${KH_HACKNAME} libkh5 "" "couldn't detect which eips tag to use for hack '${KH_HACKNAME}'" 475 | kh_eips_tag="U" 476 | ;; 477 | esac 478 | 479 | # If loglevel is anything else than I, add it to our tag 480 | if [ "${kh_loglvl}" != "I" ] ; then 481 | kh_eips_tag="${kh_eips_tag} ${kh_loglvl}" 482 | fi 483 | 484 | # Tag our message 485 | kh_eips_string="${kh_eips_tag} ${kh_eips_string}" 486 | 487 | # Can we use FBInk? 488 | if kh_has_fbink ; then 489 | kh_fbink_print "${kh_eips_string}" 490 | else 491 | kh_eips_print "${kh_eips_string}" 492 | fi 493 | fi 494 | } 495 | 496 | ## Fatal error logging 497 | kh_die() 498 | { 499 | # We need at least two args 500 | if [ $# -lt 1 ] ; then 501 | f_log W ${KH_HACKNAME} libkh5 "" "not enough arguments passed to kh_die ($# while we need at least 1)" 502 | return 503 | fi 504 | 505 | kh_msg "${1}" W "${2}" "${3}" 506 | exit 0 507 | } 508 | 509 | 510 | # The great version check! 511 | # Init everything... 512 | IS_K1="false" 513 | IS_K2="false" 514 | K2_ATLEAST_20="false" 515 | K2_ATLEAST_21="false" 516 | K2_ATLEAST_22="false" 517 | K2_ATLEAST_23="false" 518 | K2_ATLEAST_24="false" 519 | K2_ATLEAST_25="false" 520 | IS_K3="false" 521 | K3_ATLEAST_30="false" 522 | K3_ATLEAST_31="false" 523 | K3_ATLEAST_32="false" 524 | K3_ATLEAST_33="false" 525 | K3_ATLEAST_34="false" 526 | IS_K4="false" 527 | K4_ATLEAST_40="false" 528 | K4_ATLEAST_41="false" 529 | IS_K5="false" 530 | K5_ATLEAST_50="false" 531 | K5_ATLEAST_51="false" 532 | K5_ATLEAST_52="false" 533 | K5_ATLEAST_53="false" 534 | K5_ATLEAST_54="false" 535 | K5_ATLEAST_55="false" 536 | K5_ATLEAST_56="false" 537 | K5_ATLEAST_57="false" 538 | K5_ATLEAST_58="false" 539 | K5_ATLEAST_59="false" 540 | K5_ATLEAST_510="false" 541 | K5_ATLEAST_511="false" 542 | K5_ATLEAST_512="false" 543 | K5_ATLEAST_513="false" 544 | K5_ATLEAST_514="false" 545 | K5_ATLEAST_515="false" 546 | K5_ATLEAST_516="false" 547 | 548 | kpver="$(grep '^Kindle [2345]' /etc/prettyversion.txt 2>&1)" 549 | if [ $? -ne 0 ] ; then 550 | kh_msg "couldn't detect the kindle major version!" W q 551 | # Try to at least get the model... 552 | kmfc="$(cut -c1 /proc/usid)" 553 | if [ $? -ne 0 ] ; then 554 | kh_msg "couldn't detect the kindle model!" W q 555 | else 556 | if [ "${kmfc}" == "B" ] || [ "${kmfc}" == "9" ] ; then 557 | kmodel="$(cut -c3-4 /proc/usid)" 558 | case "${kmodel}" in 559 | "01" ) 560 | IS_K1="true" 561 | ;; 562 | "02" | "03" | "04" | "05" | "09" ) 563 | IS_K2="true" 564 | ;; 565 | "08" | "06" | "0A" ) 566 | IS_K3="true" 567 | ;; 568 | "0E" | "23" ) 569 | IS_K4="true" 570 | ;; 571 | "0F" | "11" | "10" | "12" | "24" | "1B" | "1D" | "1F" | "1C" | "20" | "D4" | "5A" | "D5" | "D6" | "D7" | "D8" | "F2" | "17" | "60" | "F4" | "F9" | "62" | "61" | "5F" | "C6" | "DD" | "13" | "54" | "2A" | "4F" | "52" | "53" ) 572 | IS_K5="true" 573 | ;; 574 | * ) 575 | kh_msg "unknown older kindle model (${kmodel})!" W q 576 | ;; 577 | esac 578 | else 579 | # Try the new device ID scheme... 580 | kmodel="$(cut -c4-6 /proc/usid)" 581 | case "${kmodel}" in 582 | "0G1" | "0G2" | "0G4" | "0G5" | "0G6" | "0G7" | "0KB" | "0KC" | "0KD" | "0KE" | "0KF" | "0KG" | "0LK" | "0LL" | "0GC" | "0GD" | "0GR" | "0GS" | "0GT" | "0GU" | "0DU" | "0K9" | "0KA" | "0LM" | "0LN" | "0LP" | "0LQ" | "0P1" | "0P2" | "0P6" | "0P7" | "0P8" | "0S1" | "0S2" | "0S3" | "0S4" | "0S7" | "0SA" | "0PP" | "0T1" | "0T2" | "0T3" | "0T4" | "0T5" | "0T6" | "0T7" | "0TJ" | "0TK" | "0TL" | "0TM" | "0TN" | "102" | "103" | "16Q" | "16R" | "16S" | "16T" | "16U" | "16V" | "10L" | "0WF" | "0WG" | "0WH" | "0WJ" | "0VB" | "11L" | "0WQ" | "0WP" | "0WN" | "0WM" | "0WL" | "1LG" | "1Q0" | "1PX" | "1VD" | "219" | "21A" | "2BH" | "2BJ" | "2DK" | "22D" | "25T" | "23A" | "2AQ" | "2AP" | "1XH" | "22C" | "27J" | "2BL" | "263" | "227" | "2BM" | "23L" | "23M" | "270" ) 583 | IS_K5="true" 584 | ;; 585 | * ) 586 | kh_msg "unknown kindle model (${kmodel})!" W q 587 | ;; 588 | esac 589 | fi 590 | fi 591 | else 592 | # Weeee, the great case switch! 593 | khver="$(echo ${kpver} | sed -n -r 's/^(Kindle)([[:blank:]]*)([[:digit:].]*)(.*?)$/\3/p')" 594 | case "${khver}" in 595 | 2.0.* | 2.0 ) 596 | IS_K2="true" 597 | K2_ATLEAST_20="true" 598 | ;; 599 | 2.1.* | 2.1 ) 600 | IS_K2="true" 601 | K2_ATLEAST_20="true" 602 | K2_ATLEAST_21="true" 603 | ;; 604 | 2.2.* | 2.2 ) 605 | IS_K2="true" 606 | K2_ATLEAST_20="true" 607 | K2_ATLEAST_21="true" 608 | K2_ATLEAST_22="true" 609 | ;; 610 | 2.3.* | 2.3 ) 611 | IS_K2="true" 612 | K2_ATLEAST_20="true" 613 | K2_ATLEAST_21="true" 614 | K2_ATLEAST_22="true" 615 | K2_ATLEAST_23="true" 616 | ;; 617 | 2.4.* | 2.4 ) 618 | IS_K2="true" 619 | K2_ATLEAST_20="true" 620 | K2_ATLEAST_21="true" 621 | K2_ATLEAST_22="true" 622 | K2_ATLEAST_23="true" 623 | K2_ATLEAST_24="true" 624 | ;; 625 | 2.5.* | 2.5 ) 626 | IS_K2="true" 627 | K2_ATLEAST_20="true" 628 | K2_ATLEAST_21="true" 629 | K2_ATLEAST_22="true" 630 | K2_ATLEAST_23="true" 631 | K2_ATLEAST_24="true" 632 | K2_ATLEAST_25="true" 633 | ;; 634 | 2.* ) 635 | # Assume newer, to ensure forward compat 636 | IS_K2="true" 637 | K2_ATLEAST_20="true" 638 | K2_ATLEAST_21="true" 639 | K2_ATLEAST_22="true" 640 | K2_ATLEAST_23="true" 641 | K2_ATLEAST_24="true" 642 | K2_ATLEAST_25="true" 643 | ;; 644 | 3.0.* | 3.0 ) 645 | IS_K3="true" 646 | K3_ATLEAST_30="true" 647 | ;; 648 | 3.1.* | 3.1 ) 649 | IS_K3="true" 650 | K3_ATLEAST_30="true" 651 | K3_ATLEAST_31="true" 652 | ;; 653 | 3.2.* | 3.2 ) 654 | IS_K3="true" 655 | K3_ATLEAST_30="true" 656 | K3_ATLEAST_31="true" 657 | K3_ATLEAST_32="true" 658 | ;; 659 | 3.3.* | 3.3 ) 660 | IS_K3="true" 661 | K3_ATLEAST_30="true" 662 | K3_ATLEAST_31="true" 663 | K3_ATLEAST_32="true" 664 | K3_ATLEAST_33="true" 665 | ;; 666 | 3.4.* | 3.4 ) 667 | IS_K3="true" 668 | K3_ATLEAST_30="true" 669 | K3_ATLEAST_31="true" 670 | K3_ATLEAST_32="true" 671 | K3_ATLEAST_33="true" 672 | K3_ATLEAST_34="true" 673 | ;; 674 | 3.* ) 675 | IS_K3="true" 676 | K3_ATLEAST_30="true" 677 | K3_ATLEAST_31="true" 678 | K3_ATLEAST_32="true" 679 | K3_ATLEAST_33="true" 680 | K3_ATLEAST_34="true" 681 | ;; 682 | 4.0.* | 4.0 ) 683 | IS_K4="true" 684 | K4_ATLEAST_40="true" 685 | ;; 686 | 4.1.* | 4.1 ) 687 | IS_K4="true" 688 | K4_ATLEAST_40="true" 689 | K4_ATLEAST_41="true" 690 | ;; 691 | 4.* ) 692 | IS_K4="true" 693 | K4_ATLEAST_40="true" 694 | K4_ATLEAST_41="true" 695 | ;; 696 | 5.0.* | 5.0 ) 697 | IS_K5="true" 698 | K5_ATLEAST_50="true" 699 | ;; 700 | 5.1.* | 5.1 ) 701 | IS_K5="true" 702 | K5_ATLEAST_50="true" 703 | K5_ATLEAST_51="true" 704 | ;; 705 | 5.2.* | 5.2 ) 706 | IS_K5="true" 707 | K5_ATLEAST_50="true" 708 | K5_ATLEAST_51="true" 709 | K5_ATLEAST_52="true" 710 | ;; 711 | 5.3.* | 5.3 ) 712 | IS_K5="true" 713 | K5_ATLEAST_50="true" 714 | K5_ATLEAST_51="true" 715 | K5_ATLEAST_52="true" 716 | K5_ATLEAST_53="true" 717 | ;; 718 | 5.4.* | 5.4 ) 719 | IS_K5="true" 720 | K5_ATLEAST_50="true" 721 | K5_ATLEAST_51="true" 722 | K5_ATLEAST_52="true" 723 | K5_ATLEAST_53="true" 724 | K5_ATLEAST_54="true" 725 | ;; 726 | 5.5.* | 5.5 ) 727 | IS_K5="true" 728 | K5_ATLEAST_50="true" 729 | K5_ATLEAST_51="true" 730 | K5_ATLEAST_52="true" 731 | K5_ATLEAST_53="true" 732 | K5_ATLEAST_54="true" 733 | K5_ATLEAST_55="true" 734 | ;; 735 | 5.6.* | 5.6 ) 736 | IS_K5="true" 737 | K5_ATLEAST_50="true" 738 | K5_ATLEAST_51="true" 739 | K5_ATLEAST_52="true" 740 | K5_ATLEAST_53="true" 741 | K5_ATLEAST_54="true" 742 | K5_ATLEAST_55="true" 743 | K5_ATLEAST_56="true" 744 | ;; 745 | 5.7.* | 5.7 ) 746 | IS_K5="true" 747 | K5_ATLEAST_50="true" 748 | K5_ATLEAST_51="true" 749 | K5_ATLEAST_52="true" 750 | K5_ATLEAST_53="true" 751 | K5_ATLEAST_54="true" 752 | K5_ATLEAST_55="true" 753 | K5_ATLEAST_56="true" 754 | K5_ATLEAST_57="true" 755 | ;; 756 | 5.8.* | 5.8 ) 757 | IS_K5="true" 758 | K5_ATLEAST_50="true" 759 | K5_ATLEAST_51="true" 760 | K5_ATLEAST_52="true" 761 | K5_ATLEAST_53="true" 762 | K5_ATLEAST_54="true" 763 | K5_ATLEAST_55="true" 764 | K5_ATLEAST_56="true" 765 | K5_ATLEAST_57="true" 766 | K5_ATLEAST_58="true" 767 | ;; 768 | 5.9.* | 5.9 ) 769 | IS_K5="true" 770 | K5_ATLEAST_50="true" 771 | K5_ATLEAST_51="true" 772 | K5_ATLEAST_52="true" 773 | K5_ATLEAST_53="true" 774 | K5_ATLEAST_54="true" 775 | K5_ATLEAST_55="true" 776 | K5_ATLEAST_56="true" 777 | K5_ATLEAST_57="true" 778 | K5_ATLEAST_58="true" 779 | K5_ATLEAST_59="true" 780 | ;; 781 | 5.10.* | 5.10 ) 782 | IS_K5="true" 783 | K5_ATLEAST_50="true" 784 | K5_ATLEAST_51="true" 785 | K5_ATLEAST_52="true" 786 | K5_ATLEAST_53="true" 787 | K5_ATLEAST_54="true" 788 | K5_ATLEAST_55="true" 789 | K5_ATLEAST_56="true" 790 | K5_ATLEAST_57="true" 791 | K5_ATLEAST_58="true" 792 | K5_ATLEAST_59="true" 793 | K5_ATLEAST_510="true" 794 | ;; 795 | 5.11.* | 5.11 ) 796 | IS_K5="true" 797 | K5_ATLEAST_50="true" 798 | K5_ATLEAST_51="true" 799 | K5_ATLEAST_52="true" 800 | K5_ATLEAST_53="true" 801 | K5_ATLEAST_54="true" 802 | K5_ATLEAST_55="true" 803 | K5_ATLEAST_56="true" 804 | K5_ATLEAST_57="true" 805 | K5_ATLEAST_58="true" 806 | K5_ATLEAST_59="true" 807 | K5_ATLEAST_510="true" 808 | K5_ATLEAST_511="true" 809 | ;; 810 | 5.12.* | 5.12 ) 811 | IS_K5="true" 812 | K5_ATLEAST_50="true" 813 | K5_ATLEAST_51="true" 814 | K5_ATLEAST_52="true" 815 | K5_ATLEAST_53="true" 816 | K5_ATLEAST_54="true" 817 | K5_ATLEAST_55="true" 818 | K5_ATLEAST_56="true" 819 | K5_ATLEAST_57="true" 820 | K5_ATLEAST_58="true" 821 | K5_ATLEAST_59="true" 822 | K5_ATLEAST_510="true" 823 | K5_ATLEAST_511="true" 824 | K5_ATLEAST_512="true" 825 | ;; 826 | 5.13.* | 5.13 ) 827 | IS_K5="true" 828 | K5_ATLEAST_50="true" 829 | K5_ATLEAST_51="true" 830 | K5_ATLEAST_52="true" 831 | K5_ATLEAST_53="true" 832 | K5_ATLEAST_54="true" 833 | K5_ATLEAST_55="true" 834 | K5_ATLEAST_56="true" 835 | K5_ATLEAST_57="true" 836 | K5_ATLEAST_58="true" 837 | K5_ATLEAST_59="true" 838 | K5_ATLEAST_510="true" 839 | K5_ATLEAST_511="true" 840 | K5_ATLEAST_512="true" 841 | K5_ATLEAST_513="true" 842 | ;; 843 | 5.14.* | 5.14 ) 844 | IS_K5="true" 845 | K5_ATLEAST_50="true" 846 | K5_ATLEAST_51="true" 847 | K5_ATLEAST_52="true" 848 | K5_ATLEAST_53="true" 849 | K5_ATLEAST_54="true" 850 | K5_ATLEAST_55="true" 851 | K5_ATLEAST_56="true" 852 | K5_ATLEAST_57="true" 853 | K5_ATLEAST_58="true" 854 | K5_ATLEAST_59="true" 855 | K5_ATLEAST_510="true" 856 | K5_ATLEAST_511="true" 857 | K5_ATLEAST_512="true" 858 | K5_ATLEAST_513="true" 859 | K5_ATLEAST_514="true" 860 | ;; 861 | 5.15.* | 5.15 ) 862 | IS_K5="true" 863 | K5_ATLEAST_50="true" 864 | K5_ATLEAST_51="true" 865 | K5_ATLEAST_52="true" 866 | K5_ATLEAST_53="true" 867 | K5_ATLEAST_54="true" 868 | K5_ATLEAST_55="true" 869 | K5_ATLEAST_56="true" 870 | K5_ATLEAST_57="true" 871 | K5_ATLEAST_58="true" 872 | K5_ATLEAST_59="true" 873 | K5_ATLEAST_510="true" 874 | K5_ATLEAST_511="true" 875 | K5_ATLEAST_512="true" 876 | K5_ATLEAST_513="true" 877 | K5_ATLEAST_514="true" 878 | K5_ATLEAST_515="true" 879 | ;; 880 | 5.16.* | 5.16 ) 881 | IS_K5="true" 882 | K5_ATLEAST_50="true" 883 | K5_ATLEAST_51="true" 884 | K5_ATLEAST_52="true" 885 | K5_ATLEAST_53="true" 886 | K5_ATLEAST_54="true" 887 | K5_ATLEAST_55="true" 888 | K5_ATLEAST_56="true" 889 | K5_ATLEAST_57="true" 890 | K5_ATLEAST_58="true" 891 | K5_ATLEAST_59="true" 892 | K5_ATLEAST_510="true" 893 | K5_ATLEAST_511="true" 894 | K5_ATLEAST_512="true" 895 | K5_ATLEAST_513="true" 896 | K5_ATLEAST_514="true" 897 | K5_ATLEAST_515="true" 898 | K5_ATLEAST_516="true" 899 | ;; 900 | 5.* ) 901 | IS_K5="true" 902 | K5_ATLEAST_50="true" 903 | K5_ATLEAST_51="true" 904 | K5_ATLEAST_52="true" 905 | K5_ATLEAST_53="true" 906 | K5_ATLEAST_54="true" 907 | K5_ATLEAST_55="true" 908 | K5_ATLEAST_56="true" 909 | K5_ATLEAST_57="true" 910 | K5_ATLEAST_58="true" 911 | K5_ATLEAST_59="true" 912 | K5_ATLEAST_510="true" 913 | K5_ATLEAST_511="true" 914 | K5_ATLEAST_512="true" 915 | K5_ATLEAST_513="true" 916 | K5_ATLEAST_514="true" 917 | K5_ATLEAST_515="true" 918 | K5_ATLEAST_516="true" 919 | ;; 920 | * ) 921 | kh_msg "couldn't detect the kindle version!" W q 922 | ;; 923 | esac 924 | fi 925 | --------------------------------------------------------------------------------