Tuesday, September 8, 2009

Episode #59: Lions and Tigers and Shares... Oh Mount!

Ed fires the initial salvo:

I'm sure it happens all the time. A perfectly rational command shell warrior sitting in front of a cmd.exe prompt needs to get a list of mounted file systems to see what each drive letter maps to. Our hero starts to type a given command, and then backs off, firing up the explorer GUI (by running explorer.exe, naturally) and checking out the alphabet soup mapping c: to the hard drive, d: to the DVD, f: to his favorite thumb drive, and z: to his Aunt Zelda's file share (mapped across the VPN, of course). While opting to look at this information in the GUI might be tempting, I think we can all agree that it is tawdry.

So, how can you get this information at the command line? There are a multitude of options for doing so, but I do have my favorite. Before letting the cat out of the bag (ignore the scratching and muffled meows in the background) with my favorite answer, let's visit some of the possibilities.

To get a list of available local shares, you could run:

c:\> net share

Share name Resource Remark

-------------------------------------------------------------------------------
C$ C:\ Default share
IPC$ Remote IPC
ADMIN$ C:\Windows Remote Admin
The command completed successfully.

That's a fine start, but it won't show things like your DVD or thumb drives unless you share them. Also, it leaves out any shares you've mounted across the network.

Let's see... we could get some more local stuff, including DVDs and thumb drives, by running wmic:

c:\> wmic volume list brief
Capacity DriveType FileSystem FreeSpace Label Name
32210153472 3 NTFS 14548586496 * C:\
2893314048 5 UDF 0 SANS560V0809 D:\
16015360000 2 FAT32 8098086912 E:\

That's pretty cool, and even shows us full capacity and free space. But, it does have that annoying "DriveType" line with only an integer to tell us the kind of file system it is. You can look at a variety of sites for the mapping of these numbers to drive types. However... be warned! There are a couple of different mappings depending on the version of Windows you use. On my Vista box, the mapping is:

0 = Unknown
1 = No Root Directory
2 = Removable
3 = Fixed
4 = Network
5 = CD-ROM
6 = RAM Disk

Other versions of Windows are lacking the "Root Doesn't Exist" item, and all the numbers (except 0) shift down by one.

Uh... thanks, Windows, but it would be nice to get that info without having to do the cross reference. Plus, we're still missing mounted network shares from this list. Hmmm....

Well, as we discussed in Episode #42 on listing and dropping SMB sessions, to get the list of mounted shares across the network, you could run:

c:\> net use
New connections will be remembered.


Status Local Remote Network

-------------------------------------------------------------------------------
OK Z: \\10.10.10.9\c$ Microsoft Windows Network
The command completed successfully.

Gee, that's nice. It shows you the drive letter and what it's connected to. But, you know, it's missing the local stuff.

How can we get it all, in an easy-t0-type command and a nice output format? Well, we could rely on the fsutil command:

c:\> fsutil fsinfo drives

Drives: A:\ C:\ D:\ E:\ Z:\

Ahhh... nicer. At least we've got them all now. But, you know, having just the letters kinda stinks. What the heck do they actually map to? We could check individual letter mappings by running:

c:\> fsutil fsinfo drivetype z:
z: - Remote/Network Drive

But, you know, this is kind of an ugly dead end. I mean, we could write a loop around this to pull out the info we want, but it's going to be a command that no reasonable person would just type on a whim, plus it's not going have enough detail for us.

To get what we really want, let's go back to our good friend wmic, the Windows Management Instrumentation Command line tool. Instead of the "wmic volume" alias we checked out above, we'll focus on the very useful "wmic logicaldisk" alias:

c:\> wmic logicaldisk list brief
DeviceID DriveType FreeSpace ProviderName Size VolumeName
A: 2
C: 3 14548656128 32210153472 *
D: 5 0 2893314048 SANS560V0809
E: 2 8098086912 16015360000
Z: 4 3144540160 \\10.10.10.9\c$ 4285337600

Ahh... almost there. The DriveType crap still lingers, but this one is promising. We can check out the available attributes for logicaldisk by running:

c:\> wmic logicaldisk get /?

Digging around there, we can see that name, description, and providername (which shows mounted network shares) could be useful. Let's make a custom query for them:

c:\> wmic logicaldisk get name,description,providername
Description Name ProviderName
3 1/2 Inch Floppy Drive A:
Local Fixed Disk C:
CD-ROM Disc D:
Removable Disk E:
Network Connection Z: \\10.10.10.9\c$

Soooo close. It kinda stinks having the drive letter in the middle of our output, doncha think? It should start with that. But, a frustrating fact about wmic is that its output columns show up in alphabetical order by attribute name. The "D" in description comes before the "N" in name, so we see the description first. Try reversing the order in which you request the attributes in the get clause, and you will see that they always come out the same way. Bummer.... We could switch those columns around with a FOR loop and some hideous parsing, but no one would ever want to type that command.

But, there is a solution. It turns out that the drive letter is not just stored in the "name" attribute, but is also located in the "caption" attribute. And, my friends, I don't have to remind you that "C" comes before "D" in the alphabet, do I? So, yes, we can trick Windows into giving us exactly what we want by running:

c:\> wmic logicaldisk get caption,description,providername
Caption Description ProviderName
A: 3 1/2 Inch Floppy Drive
C: Local Fixed Disk
D: CD-ROM Disc
E: Removable Disk
Z: Network Connection \\10.10.10.9\c$

So, there you have it. Reasonable, typable, beautiful. Life is good.

Hal responds:

When Unix folks want to answer the "What's mounted?" question, most of them reach for the df command first:

# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/elk-root 1008M 656M 302M 69% /
tmpfs 1.9G 0 1.9G 0% /lib/init/rw
varrun 1.9G 156K 1.9G 1% /var/run
varlock 1.9G 0 1.9G 0% /var/lock
udev 1.9G 3.0M 1.9G 1% /dev
tmpfs 1.9G 324K 1.9G 1% /dev/shm
lrm 1.9G 2.4M 1.9G 1% /lib/modules/2.6.27-11-generic/volatile
/dev/sda1 236M 60M 165M 27% /boot
/dev/mapper/elk-home 130G 99G 25G 81% /home
/dev/mapper/elk-usr 7.9G 3.3G 4.2G 44% /usr
/dev/mapper/elk-var 4.0G 743M 3.1G 20% /var
/dev/scd0 43M 43M 0 100% /media/cdrom0
/dev/sdd1 150G 38G 112G 26% /media/LACIE
//server/hal 599G 148G 421G 26% /home/hal/data

Frankly, though, I find that the mount command actually provides a lot more useful data about the mounted file systems than just the amount of available space that df shows:

# mount
/dev/mapper/elk-root on / type ext3 (rw,relatime,errors=remount-ro)
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
/proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
varrun on /var/run type tmpfs (rw,nosuid,mode=0755)
varlock on /var/lock type tmpfs (rw,noexec,nosuid,nodev,mode=1777)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
fusectl on /sys/fs/fuse/connections type fusectl (rw)
lrm on /lib/modules/2.6.27-11-generic/volatile type tmpfs (rw,mode=755)
none on /proc/bus/usb type usbfs (rw,devgid=46,devmode=664)
/dev/sda1 on /boot type ext3 (rw,relatime)
/dev/mapper/elk-home on /home type ext3 (rw,relatime)
/dev/mapper/elk-usr on /usr type ext3 (rw,relatime)
/dev/mapper/elk-var on /var type ext3 (rw,relatime)
securityfs on /sys/kernel/security type securityfs (rw)
none on /proc/fs/vmblock/mountPoint type vmblock (rw)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noexec,nosuid,nodev)
gvfs-fuse-daemon on /home/hal/.gvfs type fuse.gvfs-fuse-daemon (rw,nosuid,nodev,user=hal)
/dev/scd0 on /media/cdrom0 type iso9660 (ro,nosuid,nodev,utf8,user=hal)
/dev/sdd1 on /media/LACIE type fuseblk (rw,nosuid,nodev,allow_other,blksize=4096)
//server/hal on /home/hal/data type cifs (rw,mand)

Both commands show you the various physical and logical file systems on the machine, plus information on shares (like //server/hal) and removable media devices (like /dev/scd0). But the extra file system type information (ext3, iso9660, cifs, etc) and mount options data that the mount command provides is typically more useful to auditors and forensic examiners because it provides a better picture of how the devices are actually being used.

The one thing that's missing from both the df and mount output is information about your swap areas. You need to use the swapon command to get at this information:

# swapon -s
Filename Type Size Used Priority
/dev/mapper/elk-swap partition 4194296 5488 -1

If you're running on hardware with a PC BIOS, then your OS probably also includes the fdisk command:

# fdisk -l

Disk /dev/sda: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0xed1f86f7

Device Boot Start End Blocks Id System
/dev/sda1 * 1 31 248976 83 Linux
/dev/sda2 32 19457 156039345 83 Linux

Disk /dev/sdd: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0xb90dbb65

Device Boot Start End Blocks Id System
/dev/sdd1 * 1 19457 156288321 7 HPFS/NTFS

Aside from giving you physical geometry information about how your disks are laid out, fdisk might also show you file systems that are not currently mounted.

Astute readers might have noticed a discrepancy between the output of the mount and fdisk commands. Let me add some command line options to each command to help highlight the difference:

# fdisk -l /dev/sda

Disk /dev/sda: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0xed1f86f7

Device Boot Start End Blocks Id System
/dev/sda1 * 1 31 248976 83 Linux
/dev/sda2 32 19457 156039345 83 Linux
# mount -t ext3
/dev/mapper/elk-root on / type ext3 (rw,relatime,errors=remount-ro)
/dev/sda1 on /boot type ext3 (rw,relatime)
/dev/mapper/elk-home on /home type ext3 (rw,relatime)
/dev/mapper/elk-usr on /usr type ext3 (rw,relatime)
/dev/mapper/elk-var on /var type ext3 (rw,relatime)

We see in the fdisk output that /dev/sda is split into two partitions, and we can see in the mount output that /dev/sda1 is mounted on /boot. But what are all those /dev/mapper/elk-* devices and how do they map into the apparently unused /dev/sda2 partition?

What you're seeing here is typical of a system that's using the Linux Logical Volume Manager (LVM). LVM is a mechanism for creating "soft partitions" that can be resized at will, and it also ties in with a bunch of other functionality, some of which we'll encounter shortly. Other flavors of Unix will typically have something similar, though the exact implementation may vary. The high-level concept for Linux LVM is that your file systems each live inside of a "logical volume" (LV). A set of logical volumes is a "volume group" (VG), and VGs live inside of a "physical volume" (PV). You can think of the PV as the actual physical partition on disk.

To take an example from the output above, the /home file system lives inside the LV /dev/mapper/elk-home. You can use the lvdisplay and vgdisplay commands to get information about the LV and VG, and these commands would show you that "elk-home" and all the other LVs on the system are part of the VG "elk". But in order to figure out the mapping between the VG and the PV on disk, you need to use the pvdisplay command:

# pvdisplay
--- Physical volume ---
PV Name /dev/mapper/sda2_crypt
VG Name elk
PV Size 148.81 GB / not usable 1.17 MB
Allocatable yes (but full)
PE Size (KByte) 4096
Total PE 38095
Free PE 0
Allocated PE 38095
PV UUID rOwdB9-r8Io-1IIA-ITRK-TPjE-eF98-RkGqVN

You'll note that the "PV Name" lists a device name that doesn't look like a physical partition like /dev/sda2. That's because in this case my PV is actually an encrypted file system that was created using the Linux disk encryption utilities. That means we have to go through one more level of indirection to get back to the actual physical disk partition info:

# cryptsetup status sda2_crypt
/dev/mapper/sda2_crypt is active:
cipher: aes-cbc-essiv:sha256
keysize: 256 bits
device: /dev/sda2
offset: 2056 sectors
size: 312076634 sectors
mode: read/write

Whew! So let's recap. /home is an ext3 file system inside of /dev/mapper/elk-home, which we learn from the mount command. lvdisplay would tell us which VG this volume was part of, and vgdisplay would give us more details about the "elk" VG itself. pvdisplay normally gives us the mappings between the VGs and the physical partitions, but in this case our PV is actually a logical volume inside of an encrypted file system. So we need to use cryptsetup to dump the information about the encrypted volume, including the actual physical device name. That's a lot of layers, but it's really not that awful to deal with in practice.