Skip to content

Instantly share code, notes, and snippets.

@ashevchuk
Last active May 7, 2024 00:17
Show Gist options
  • Save ashevchuk/74f7273e5f8e9868d36b1757e18f9d69 to your computer and use it in GitHub Desktop.
Save ashevchuk/74f7273e5f8e9868d36b1757e18f9d69 to your computer and use it in GitHub Desktop.
Aster MegaRAC IPMI q&d fix for broken iKVM jviewer.jnlp
#!/bin/sh
if [ "$#" -ne 3 ]; then
echo "Usage: $0 [ip address] [user name] [password]"
exit 1
fi
IP=$1
IPMI_USER=$2
IPMI_PASS=$3
OUTFILE=/tmp/${IP}_jviewer.jnlp
COOKIE=$(curl "http://${IP}/rpc/WEBSES/create.asp" --silent --raw --data "WEBVAR_USERNAME=${IPMI_USER}&WEBVAR_PASSWORD=${IPMI_PASS}" -o - | perl -ne "m/\'SESSION\_COOKIE\'\s\:\s\'(.*?)\'/sg ? print \$1 : ();")
TOKEN=$(curl "http://${IP}/rpc/getsessiontoken.asp" -H "Cookie: SessionCookie=${COOKIE}" --silent --raw -o - | perl -ne "m/\'STOKEN\'\s\:\s\'(.*?)\'/sg ? print \$1 : ();")
(
cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="https://${IP}/Java">
<information>
<title>JViewer</title>
<vendor>American Megatrends, Inc.</vendor>
<description kind="one-line">JViewer Console Redirection Application</description>
<description kind="tooltip">JViewer Console Redirection Application</description>
<description kind="short">
JViewer enables a user to view the video display of managed server via KVM.
It also enables the user to redirect his local keyboard, mouse for managing the server remotely.
</description>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.5+"/>
<jar href="release/JViewer.jar"/>
</resources>
<resources os="Windows" arch="amd64">
<j2se version="1.5+"/>
<nativelib href="release/Win64.jar"/>
</resources>
<resources os="Windows" arch="x86">
<j2se version="1.5+"/>
<nativelib href="release/Win32.jar"/>
</resources>
<resources os="Linux" arch="x86">
<j2se version="1.5+"/>
<nativelib href="release/Linux_x86_32.jar"/>
</resources>
<resources os="Linux" arch="i386">
<j2se version="1.5+"/>
<nativelib href="release/Linux_x86_32.jar"/>
</resources>
<resources os="Linux" arch="x86_64">
<j2se version="1.5+"/>
<nativelib href="release/Linux_x86_64.jar"/>
</resources>
<resources os="Linux" arch="amd64">
<j2se version="1.5+"/>
<nativelib href="release/Linux_x86_64.jar"/>
</resources>
<application-desc>
<argument>${IP}</argument>
<argument>7578</argument>
<argument>${TOKEN}</argument>
<argument>${COOKIE}</argument>
</application-desc>
</jnlp>
EOF
) > $OUTFILE
javaws -nosecurity -jnlp $OUTFILE >/dev/null & disown && sleep 1 && rm -f $OUTFILE
@joshua-software-dev
Copy link

I made a slightly more robust version of these scripts in python that should work on python 2.7 and python 3.3+. I needed it to work on windows and prefer to keep my non-dev machines without bash on windows/cygwin/wsl.

#! /usr/bin/env python

import os
import re
import shutil
import subprocess
import sys
import tempfile
import textwrap
import time

from argparse import ArgumentParser
from getpass import getpass

if sys.version[0] == '2':
    from urllib import urlencode
    from urllib2 import urlopen, Request
else:
    from urllib.parse import urlencode
    from urllib.request import urlopen, Request


parser = ArgumentParser()
hostip = parser.add_mutually_exclusive_group(required=False)
hostip.add_argument('-ip', '--hostip', action='store')
hostip.add_argument('HOST_IP', action='store', nargs='?')

username = parser.add_mutually_exclusive_group(required=False)
username.add_argument('-u', '--username', action='store')
username.add_argument(
    'USERNAME', 
    action='store', 
    help='Can also be provided interactively to hide from console history.', 
    nargs='?'
)

passwd = parser.add_mutually_exclusive_group(required=False)
passwd.add_argument('-pw', '--password', action='store')
passwd.add_argument(
    'PASSWORD', 
    action='store', 
    help='Can also be provided interactively to hide from console history.',
    nargs='?'
)

parser.add_argument(
    '-l', 
    '--launch', 
    action='store_true', 
    default=False, 
    help='Launch generated jviewer file with javaws after generating it.'
)

pargs = parser.parse_args()

ip = pargs.hostip or pargs.HOST_IP or input('Input host IP: ')
ipmi_user = pargs.username or pargs.USERNAME or getpass('Input username: ')
ipmi_pass = pargs.password or pargs.PASSWORD or getpass('Input password: ')

resp_search = re.compile(r"'(SESSION_COOKIE|STOKEN|SESSION_TOKEN)' : '(.+)'")

cookie_req = Request(
    data=urlencode(
        {
            'WEBVAR_USERNAME': ipmi_user, 
            'WEBVAR_PASSWORD': ipmi_pass
        }
    ).encode('utf-8'),
    url='http://{}/rpc/WEBSES/create.asp'.format(ip)
)
cookie_raw = urlopen(cookie_req).read().decode('utf-8')
cookie = resp_search.search(cookie_raw).groups()[1]

token_req = Request(
    headers={'Cookie': 'SessionCookie={}'.format(cookie)}, 
    url='http://{}/rpc/getsessiontoken.asp'.format(ip)
)
token_raw = urlopen(token_req).read().decode('utf-8')
token = resp_search.search(token_raw).groups()[1]

jnlp_template = """\
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="https://{ip}/Java">
    <information>
        <title>JViewer</title>
        <vendor>American Megatrends, Inc.</vendor>
        <description kind="one-line">
            JViewer Console Redirection Application
        </description>
        <description kind="tooltip">
            JViewer Console Redirection Application
        </description>
        <description kind="short">
            JViewer enables a user to view the video display 
            of managed server via KVM. It also enables the 
            user to redirect his local keyboard, mouse for 
            managing the server remotely.
        </description>
    </information>
    <security>
        <all-permissions/>
    </security>
    <resources>
        <j2se version="1.5+"/>
        <jar href="release/JViewer.jar"/>
    </resources>
    <resources os="Windows" arch="amd64">
        <j2se version="1.5+"/>
        <nativelib href="release/Win64.jar"/>
    </resources>
    <resources os="Windows" arch="x86">
        <j2se version="1.5+"/>
        <nativelib href="release/Win32.jar"/>
    </resources>
    <resources os="Linux" arch="x86">
        <j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_32.jar"/>
    </resources>
    <resources os="Linux" arch="i386">
        <j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_32.jar"/>
    </resources>
    <resources os="Linux" arch="x86_64">
        <j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_64.jar"/>
    </resources>
    <resources os="Linux" arch="amd64">
        <j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_64.jar"/>
    </resources>
    <application-desc>
        <argument>{ip}</argument>
        <argument>7578</argument>
        <argument>{token}</argument>
        <argument>{cookie}</argument>
    </application-desc>
</jnlp>
""".format(ip=ip, token=token, cookie=cookie)

if pargs.launch:
    try:
        temp_dir = tempfile.mkdtemp()

        with open(os.path.join(temp_dir, 'jviewer.jnlp'), 'w+') as fh:
            fh.write(jnlp_template)
            fh.flush()
            os.fsync(fh.fileno())

        popen_kwargs = {
            'close_fds': True,
            'shell': False, 
            'stderr': None, 
            'stdin': None, 
            'stdout': None
        }

        if sys.platform == 'win32':
            # subprocess.DETACHED_PROCESS = 8, in python 3.7+
            # Raw value is needed for python 2/python 3.6-
            popen_kwargs['creationflags'] = 8

        proc = subprocess.Popen(
            [
                'javaws', 
                os.path.join(temp_dir, 'jviewer.jnlp')
            ], 
            **popen_kwargs
        )
    finally:
        time.sleep(5)
        shutil.rmtree(temp_dir)
else:
    with open('jviewer.jnlp', 'w+') as fh:
        fh.write(jnlp_template)

Examples (all equivalent):

python ipmi.py 192.168.1.45 admin password -l
python ipmi.py -ip 192.168.1.45 -u admin -pw password -l
python ipmi.py --launch
>Input host IP: 192.168.1.45
>Input username:
>Input password:

Hope its useful for someone else. Only personally managed to get it running with jre8-openjdk and icedtea-web on arch, and jre7 on windows, didn't test macos.

@cavemandaveman
Copy link

These all fix the jnlp file, but I still get "Invalid Session token" when trying to connect. Anyone else experience the same?

@mayli
Copy link

mayli commented Apr 26, 2021

For my Chenbro NR12000(S5512), I had to use a really old JDK (maybe 7) to avoid the "Invalid Session token" error, however I am unable to get any video out.

@ashevchuk
Copy link
Author

If you receive an "Invalid Session token", check the functionality of the Web interface of your IPMI.

@martindorey
Copy link

Thank you thank you thank you. I did struggle with this:

You are trying to get resource https://<ip>/Java/release/JViewer.jar but it is not in cache and could not be downloaded. Attempting to continue, but you may expect failure
JAR https://<ip>/Java/release/JViewer.jar not found. Continuing.
JAR https://<ip>/Java/release/Linux_x86_64.jar not found. Continuing.
JAR https://<ip>/Java/release/JViewer.jar not found. Continuing.
JAR https://<ip>/Java/release/Linux_x86_64.jar not found. Continuing.
netx: Initialization Error: Could not initialize application. (Fatal: Initialization Error: Unknown Main-Class. Could not determine the main class for this application.)
net.sourceforge.jnlp.LaunchException: Fatal: Initialization Error: Could not initialize application. The application has not been initialized, for more information execute javaws from the command line.
	at net.sourceforge.jnlp.Launcher.createApplication(Launcher.java:813)
	at net.sourceforge.jnlp.Launcher.launchApplication(Launcher.java:532)
	at net.sourceforge.jnlp.Launcher$TgThread.run(Launcher.java:936)
Caused by: net.sourceforge.jnlp.LaunchException: Fatal: Initialization Error: Unknown Main-Class. Could not determine the main class for this application.
	at net.sourceforge.jnlp.runtime.JNLPClassLoader.initializeResources(JNLPClassLoader.java:704)
	at net.sourceforge.jnlp.runtime.JNLPClassLoader.<init>(JNLPClassLoader.java:285)
	at net.sourceforge.jnlp.runtime.JNLPClassLoader.createInstance(JNLPClassLoader.java:357)
	at net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:429)
	at net.sourceforge.jnlp.runtime.JNLPClassLoader.getInstance(JNLPClassLoader.java:403)
	at net.sourceforge.jnlp.Launcher.createApplication(Launcher.java:805)
	... 2 more

... until I lit upon:

--- ipmi.py.orig	2021-05-23 16:15:46.067942738 -0700
+++ ipmi.py	2021-05-22 19:42:36.380118858 -0700
@@ -80,7 +80,7 @@
 
 jnlp_template = """\
 <?xml version="1.0" encoding="UTF-8"?>
-<jnlp spec="1.0+" codebase="https://{ip}/Java">
+<jnlp spec="1.0+" codebase="http://{ip}/Java">
     <information>
         <title>JViewer</title>
         <vendor>American Megatrends, Inc.</vendor>
martind@sirius:~/tmp/D148004$ ```

@mayli
Copy link

mayli commented May 24, 2021

The both web interface and ipmi interface work fine, just the console redirection refuse to work with "Invalid Session token" :/

@colbyboles
Copy link

For my Chenbro NR12000(S5512), I had to use a really old JDK (maybe 7) to avoid the "Invalid Session token" error, however I am unable to get any video out.

Did you ever get this working? I have 24 NR12000s I would like to control remotely via IPMI.

@igorekdp
Copy link

After update BMC to version 7012 we can download work jnlp file and connect to server

Firmware BMC: https://www.tyan.com/Motherboards=S7012=S7012WGM4NR=downloads=EN (solution find there https://serverfault.com/questions/309950/i-keep-getting-an-ipmi-error-when-doing-console-redirection)

@igorekdp
Copy link

igorekdp commented Jul 29, 2022

<?xml` version="1.0" encoding="UTF-8"?>

<jnlp` spec="1.0+" codebase="http://10.20.52.11/Java">
    <information>
        <title>JViewer</title>
        <vendor>American Megatrends, Inc.</vendor>
        <description kind="one-line">JViewer Console Redirection Application</description>
        <description kind="tooltip">JViewer Console Redirection Application</description>
        <description kind="short">
            JViewer enables a user to view the video display of managed server via KVM.  
            It also enables the user to redirect his local keyboard, mouse for managing the server remotely.
        </description>
    </information>
	<security>
		<all-permissions/>
	</security>
    <resources>
        <j2se version="1.5+"/>
        <jar href="release/JViewer.jar"/>
    </resources>
    <resources os="Windows" arch="amd64">
       <j2se version="1.5+"/>
       <nativelib href="release/Win64.jar"/>
    </resources>
    <resources os="Windows" arch="x86">
    	<j2se version="1.5+"/>
    	<nativelib href="release/Win32.jar"/>
    </resources>    
    <resources os="Linux" arch="x86">
    	<j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_32.jar"/>
    </resources>    
    <resources os="Linux" arch="i386">
    	<j2se version="1.5+"/>
        <nativelib href="release/Linux_x86_32.jar"/>
    </resources>
    <resources os="Linux" arch="x86_64">
            <j2se version="1.5+"/>
    <nativelib href="release/Linux_x86_64.jar"/>
    </resources>
    <resources os="Linux" arch="amd64">
            <j2se version="1.5+"/>
    <nativelib href="release/Linux_x86_64.jar"/>
    </resources>
    <resources os="Mac OS X" arch="i386">
        <j2se version="1.5+"/>
        <nativelib href="release/Mac32.jar"/>
    </resources>
    <application-desc>
        <argument>10.20.52.11</argument>
        <argument>7578</argument>
        <argument>l09mePTM4wWfnhDQ�<argument>6R3x1K8UQblHNFUEDMakCtqCZ2RXkpci003</argument>
</argument>
    </application-desc>
</jnlp>

@joaormatos
Copy link

joaormatos commented May 7, 2024

A way to avoid using Webstart and having to deal with its security policies is to run the main JAR directly with Java.

Manually grab the main JAR (JViewer.jar) and the JAR with the native libs for your platform, extracting the native libs JAR into some directory (say, "libs"; it just contains shared libraries) and then run something like:

LD_LIBRARY_PATH="$PWD/libs" java -jar JViewer.jar

Just add the arguments that you'd see getting passed in the jnlp.
Namely, the BMC IP address, the port (7578) and any token/cookies.

Taking the jnlp in the previous comment as example:

wget http://10.20.52.11/Java/release/JViewer.jar
wget http://10.20.52.11/Java/release/Linux_x86_64.jar
mkdir libs
unzip -d libs Linux_x86_64.jar
LD_LIBRARY_PATH="$PWD/libs" java -jar JViewer.jar 10.20.52.11 7578 $'l09mePTM4wWfnhDQ\002' 6R3x1K8UQblHNFUEDMakCtqCZ2RXkpci003

I tested this method with a Tyen S7002. It only provides 32 bit versions of native libs, so I did this in a dedicated 32 bit Debian bookworm VM.
Seems to work fine on the distro's current openjdk JRE (version 17.0.11), but I didn't do any extensive tests.
It would probably work fine on an x86_64 system with multilib, as long as you used a 32 bit JRE.

Also note that you may run into a problem where the BMC system hits some limit in the number of sessions/tokens and will stop giving you additional tokens. Avoid spamming the same BMC with requests while debugging your scripts or risk getting locked out of using KVM for that host.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment