NSLU2-Linux
view · edit · print · history

UPDATE: See this thread on linksysinfo.org for information about a modified firmware by the same author which supports not only telnet, but also dropbear (ssh secure shell and file transfer), ext2 filesystems, custom startup scripts and more.

This page describes how to get a Telnet daemon (telnetd) running on a NAS200. You won't need the serial port so this won't void the warranty. However, you do this procedure at your own risk and I won't pay for your repairs. If you do something wrong and brick your box, you're on your own; there are currently (as of January 20th, 2008) no known easy ways to unbrick a NAS200.

You can download the sources from the author's website: http://www.goudsm.it/nas200_telnetd_source.tgz md5sum 000170bf83b4faff522475b7a2ccc128. That tarball includes a script to download and unpack the Linksys sources if you don't already have them, and to unpack the necessary files into the source tree.


What we will accomplish here, and how

If you're on this website, you're probably interested in making the NAS200 do more than what it was designed to do. One of the first things you probably want is to get shell access to the device.

At the time of this writing, there is no known way to get shell access if your NAS runs unmodified (V34R62) firmware.

The good news is that Linksys not only made the GPL source code available (as they should), but they went one step further and generously put the entire ROM file system into the package, including the Twonkymedia server, a correctly configured GCC compiler and the shell scripts to build a valid boot image that you can download into the box without even walking away from your Linux-based PC.

A quick perusal of the firware sources reveals that there simply is no telnet daemon on the box. Nor is there a dropbear or any other program that allows shell access. And as far as I could tell, there is no way to make the NAS200 execute scripts or programs on the harddisk. So, short of opening the box and using the serial port (which voids the warranty because you have to break a seal), the only way to get shell access is to build a modified firmware that runs a Telnet daemon (telnetd).

To accomplish this, we'll need to do the following:

To do this, you will need a PC running Linux to which you have root access. You will need some programming tools such as Gnu Make to be able to build the firmware, but if you're here, you probably already have those or you know how to get them. If not, you're probably not qualified to do this, so get some help.

Unpack the firmware source

You can download the NAS200 (version 34R62) firmware source code from the linksys FTP server. You should unpack the file in the usual way:

tar xfvz NAS200_V34R62.tgz

This will create a directory NAS200_V34R62_GPL. If you want, you can cd to that directory, use su to become root and type: make to build an unmodified firmware that you can download to your NAS200 to "test the waters".

A make takes about 20 minutes on my 2.8GHz Pentium4 without hyperthreading. The resulting firmware works virtually flawlessly on my system, except for a problem with the Twonky database which seems to get garbled by the self-compiled firmware. The media server is not critical to my use so I will research this later.

Modify Makefile and scripts

The source directory contains the most important Makefile of the system. It enumerates all directories to build all the programs that will end up in the target filesystem. As a gesture to developer communities like us, Linksys included a tarball of the target filesystem in the source/mipsel directory. The source/Makefile unpacks this tarball before doing make install in all program directories. Then it makes an image of the tree and erases the directory.

We will want to make a few modifications to the target file system, so we're going to modify the Makefile:

  • The default filesystem now gets unpacked by make install, we'll change it so it gets unpacked by make clean
  • The XFS image is now made by make install, we'll change it so it gets made by make image
  • The default filesystem directory is now deleted by make install, we will change this so it won't happen.

Change source/Makefile as follows:

  • Move the install: target name to below the untar commands and put the untar commands into a new cleantarget: target name
  • Change the -R option in the chown command to -Rh to prevent chown from trying to follow symlinks into your host file system
  • Move the image: target name to above the line starting with ./mksquashfs.
  • Add the -noappend option to the ./makesquashfs command so that the file system is started from scratch each time you do make image.
  • Remove (or comment out) the rm command after ./mksquashfs so that the target directory doesn't get thrown away.
  • Add cleantarget as dependency of the clean: target

Here's a diff -u to accomplish this:

--- org/NAS200_V34R62_GPL/source/Makefile     2007-06-21 20:10:39.000000000 -0700
+++ new/NAS200_V34R62_GPL/source/Makefile     2008-01-22 12:55:46.000000000 -0700
@@ -49,7 +49,7 @@
        echo "-----------------------------------------------------------------"; \
        make -C $$i || exit 1 ;                                                   \
        done
-install:
+cleantarget:
        rm -rf $(PLATFORMDIR)/target/
 ifneq ($(MEDIA_SERVER), __YES__)
 ifeq ($(SLIM_SERVER), __YES__)
@@ -60,6 +60,7 @@
 else
        tar -xvzf $(PLATFORMDIR)/target-default-media.tgz -C $(PLATFORMDIR)/
 endif
+install:
        @for i in ${SUBLIBS} ;  do                                                    \
        echo "-----------------------------------------------------------------"; \
        echo -e "\033[;35m                         $$i                 \033[;0m"; \
@@ -75,16 +76,15 @@
        cp -f $(LINUXDIR)/fs/nls/nls_cp932.ko $(PLATFORMDIR)/target/lib/
        cp -f $(LINUXDIR)/fs/nls/nls_cp949.ko $(PLATFORMDIR)/target/lib/
        cp -f $(LINUXDIR)/fs/nls/nls_cp950.ko $(PLATFORMDIR)/target/lib/
-       chown root.root $(PLATFORMDIR)/target -R
+       chown root.root $(PLATFORMDIR)/target -Rh
        rm -f $(PLATFORMDIR)/romdisk
        $(STRIP) $(PLATFORMDIR)/target/lib/*.0.0
-       ./mksquashfs $(PLATFORMDIR)/target $(PLATFORMDIR)/romdisk -le -noI -no-fragments -lzma
-       rm -rf $(PLATFORMDIR)/target
 image:
+       ./mksquashfs $(PLATFORMDIR)/target $(PLATFORMDIR)/romdisk -le -noI -no-fragments -lzma -noappend
        cp -f $(LINUXDIR)/arch/i386/boot/bzImage ../images
        cp $(PLATFORMDIR)/romdisk ../images  -f

-clean:
+clean: cleantarget
        for i in ${SUBLIBS} ; do make -C $$i clean || exit 1 ; done
        for i in ${SUBDIRS} ; do make -C $$i clean || exit 1 ; done

Add device nodes and softlinks

The telnetd program uses the PTS terminals which are compiled into the kernel (in the Busybox config, CONFIG_FEATURE_DEVPTS is enabled); however the file system doesn't contain device nodes for the PTS terminal. All we need to do to fix this is run a few mknod commands after we unpack the filesystem.

  • If you haven't done so yet, run make cleantarget in the source directory to unpack the file system (any previous modifications in the filesystem will be lost).
  • In the source/mipsel/target/dev directory, run the command: mknod ptmx c 5 2
  • In the source/mipsel/target/dev/pts directory, run the command: mknod 0 c 136 0

Note: The above will only allow one terminal to be open, i.e. only one Telnet daemon can run. If you want to allow multiple simultaneous Telnet sessions, add more device nodes in the dev/pts directory, e.g. for x in 0 1 2 3 4 5 6 7;do mknod $x c 136 $x;done .

I will explain below that apparently the system expects telnetd to be in the /usr/sbin:

  • In the source/mipsel/target/usr/sbin, run the command: ln -s ../../bin/busybox telnetd

Modify Busybox configuration

The Busybox version that's in the NAS200 tree is quite old (1.00-rc2), but it works fine. Linksys included a .config file but on my system, make menuconfig didn't work so we have to modify the configuration manually without help from the menu system.

To do this, edit the source/busybox-1.00-rc2/.config file:

  • Enable CONFIG_TELNETD
  • Add and enable CONFIG_TELNETD_INETD

Again, here's a diff -u:

--- org/NAS200_V34R62_GPL/source/busybox-1.00-rc2/.config     2007-05-23 19:02:28.000000000 -0700
+++ new/NAS200_V34R62_GPL/source/busybox-1.00-rc2/.config     2008-01-20 13:42:08.000000000 -0700
@@ -321,7 +321,8 @@
 CONFIG_TELNET=y
 CONFIG_FEATURE_TELNET_TTYPE=y
 CONFIG_FEATURE_TELNET_AUTOLOGIN=y
-# CONFIG_TELNETD is not set
+CONFIG_TELNETD=y
+CONFIG_FEATURE_TELNETD_INETD=y
 # CONFIG_TFTP is not set
 # CONFIG_TRACEROUTE is not set
 # CONFIG_VCONFIG is not set
  CONFIG_TELNETD=y

Fix Busybox bug

The telnetd code of the Busybox code that's part of the NAS200 source tree causes a segmentation fault when it tries to copy a NULL pointer that is returned by the ptsname(3) system function.

The ptsname(3) function determines what the slave device is that belongs to a terminal device, but it's not thread-safe. In the kernel that's part of the NAS200 source package, ptsname() fails, but its thread-safe equivalent ptsname_r(3) works. We'll have to change the program so that it uses the ptsname_r(3) instead of ptsname(3):

  • In source/busybox-1.00-rc2/networking/telnetd.c, modify the line strcpy(line, ptsname(p)); to read ptsname_r(p, line, 32);.

Here's a diff -u:

--- org/NAS200_V34R62_GPL/source/busybox-1.00-rc2/networking/telnetd.c   2006-07-31 19:04:04.000000000 -0700
+++ new/NAS200_V34R62_GPL/source/busybox-1.00-rc2/networking/telnetd.c   2008-01-19 23:44:19.000000000 -0700
@@ -197,7 +197,7 @@
        if (p > 0) {
                grantpt(p);
                unlockpt(p);
-               strcpy(line, ptsname(p));
+               ptsname_r(p, line, 32);
                return(p);
        }
 #else

Hardcoding the value 32 is slighlty nasty but is a quick solution which is relatively safe because the function is static and only gets called from one place. It's no less unsafe that using strcpy.

Modify inetd configuration

One of the first programs that gets executed as part of the boot process, is a (closed-source) program called /usr/sbin/rc.bootbin. This program apparently reads the configuration from flash memory (/dev/mtd2) and mounts the disks as necessary. There appears to be a setting in /etc/CGI_ds.conf telnet_enable=no that might enable a telnetd; if you can find a way to change that setting from the web pages, let us know. Apparently (judging from a look at /usr/sbin/rc.bootbin with a hex editor), rc.bootbin modifies the inetd configuration in /etc/inetd.conf to allow a telnet daemon to run as /usr/sbin/telnetd.

/usr/sbin/rc.bootbin writes the /etc/inetd.conf from scratch, depending on whether FTP (and telnetd) are enabled in the configuration. That means we can't modify the inetd.conf file directly. Instead, we'll modify the startup scripts so that after rc.bootbin runs but before the startup scripts start inetd, the configuration is changed so that telnetd is allowed:

  • In source/mipsel/target/etc.default/rc.d, modify the rc.1 file and insert echo "telnet stream tcp nowait root /usr/sbin/telnetd -l /bin/sh" >>/etc/inetd.conf below the command that starts rc.bootbin.
--- org/NAS200_V34R62_GPL/source/mipsel/target/etc.default/rc.d/rc.1  2007-04-05 01:15:52.000000000 -0700
+++ new/NAS200_V34R62_GPL/source/mipsel/target/etc.default/rc.d/rc.1  2008-01-20 11:21:51.000000000 -0700
@@ -10,6 +10,7 @@
 mkdir -p /mnt/backup 2>/dev/null
 mkdir -p /mnt/queue 2>/dev/null
 /bin/echo  "Starting Set CGI_ds.conf:"; /usr/sbin/rc.bootbin
+echo "telnet   stream  tcp     nowait  root    /usr/sbin/telnetd -l /bin/sh" >>/etc/inetd.conf
 /bin/echo  "Restore time and timezone:"; /etc/rc.d/rc.rstimezone
 /bin/echo  "Restore usrgrpshares:"; /usr/sbin/reset_ugs
 /bin/echo  "Starting WEB Server:"; /etc/rc.d/rc.thttpd

ATTENTION The line that gets added to the inetd configuration runs telnetd with /bin/sh as shell. This is very unsafe, because anyone can telnet to the box and they will be root. If you remove the -l /bin/sh option, the telnet daemon will run /bin/login instead, so that you have to identify yourself. This is still unsafe: The password that you send over the network will be unencrypted and can be picked up by anyone who knows how to use a program such as Wireshark. Besides, the root account has a password (which is unknown to me) so you can only log in as one of the predefined users or a user name you defined.

You can modify the script line to "install" telnetd conditionally if you are concerned about security. For example you could do:

# Conditional code for rc.1
if [ -f /harddisk/volume_1/data/telnetd_enable.txt ]
then
  echo "telnet stream tcp nowait root /usr/sbin/telnetd -l /bin/sh" >>/etc/inetd.conf
fi

Then, whenever the box boots up it will check if a file telnetd_enable.txt exists in the root directory of the DISK 1 share, and will start telnetd only if it does. Note that if you do this, you will have to remove the file and restart the box to turn telnetd off. Of course now you have telnet you can also simply edit the /etc/inetd.conf file with vi and restart inetd with /etc/rc.d/rc.xinetd restart.

Build everything and download it

Now you are ready to build your firmware image:

  • In the root of your download (i.e. the NAS200_V34R62 directory), type make.
  • Open the Upgrade Firmware page of your NAS200 in your favourite web browser and browse to images/NAS200_V34R62.bin and click Start Upgrade.

Unless you did something stupid that keeps the box from booting, you can always return to the original firmware.

view · edit · print · history · Last edited by Jac Goudsmit.
Based on work by Jac Goudsmit and fcarolo.
Originally by Jac Goudsmit.
Page last modified on April 02, 2008, at 12:54 PM