Thursday, July 10, 2014

How to assign ACLs to Cisco VPN user via RADIUS

While setting up per user ACLs in RADIUS for my VPN users I noticed some issues with current on-line documentation. I am using a Cisco ASA 9.2(2) as the VPN concentrator and FreeRADIUS 3.0.2 as the RADIUS server.  In the RADIUS users file you need to add your ACLs in this manner:

testuser1  Cleartext-Password := "testme"
   Cisco-AVPair = "ip:inacl#101=permit ip any 192.168.1.0 255.255.255.0",
   Cisco-AVPair += "ip:inacl#102=deny ip any any",
   Service-Type = Framed-User,
   Framed-Protocol = PPP,
   Framed-IP-Address = 192.168.255.97,
   Framed-IP-Netmask = 255.255.255.0,
   Reply-Message = "This is a test message"


You should notice the use of "ip:inacl" not "ip.inacl" as most current on-line documentation suggests.  Also, make sure you use "+=" for every line other than the first. 

Thursday, July 3, 2014

Cisco AnyConnect Secure Mobility Client Authentication Errors

I recently ran in to a problem where I would get the dreaded "User not authorized for AnyConnect Client access, contact your administrator" error message from my Cisco ASA running version 9.2(2) when trying to connect to the VPN service (IPSec, IKEv2).  The really frustrating part was my Mac could connect just fine, but my Windows VM would not. After some research I figured out what the fundamental problem was and what was causing it.

The main issue was the AnyConnect Client Profile was not getting downloaded to the Windows machine. The reason my Mac worked, is I had successfully downloaded it at some point and it was cached. On Windows 7 you can find the file in the following directory:
C:\ProgramData\Cisco\Cisco AnyConnect Secure Mobility Client\Profile>

On Mac you can find the same profille in:
/opt/cisco/anyconnect/profile->

The reason it was not getting downloaded is I had turned off the SSL Access configuration in the AnyConnect Connection Profiles interface section, since I was not using it.  You turn this back on, and viola it works. So if you are getting the dreaded error, check to see if you have your AnyConnect Client Profile first.

Tuesday, April 29, 2014

Working With Golang Array Slices

In the Go language a Slice is equivalent to the way a Perl/Python developer might think of an Array.  Yes, there is an actual Array under the covers of a Slice, but you cannot do much with them. So in Go, most people works with a Slice.  So if you are new to Go and coming from Perl/Python or the like, when you think you want an Array, you really want a Slice.  

Example
package main

import (
 "fmt"
)

func main() {
 
 // This is how you would declare and initialize a Slice at the same time.
 var aSliceOfStrings1 = []string{"a", "b", "c"}
 fmt.Println(aSliceOfStrings1[1])
 // This will print "b"


 // This is a shorthand way of declaring and initializing a Slice at the same time.
 aSliceOfStrings2 := []string{"c", "d",}
 fmt.Println(aSliceOfStrings2[1])
 // This will print "d" 

 
 // To create a slice but not initialize it you would use the make function.  This allows to define the
 // size and the optional capacity (defaults to length) at the same time.
 aSliceOfStrings3 := make([]string, 5, 10)
 aSliceOfStrings3[0] = "a"
 aSliceOfStrings3[1] = "b"
 aSliceOfStrings3[2] = "c"
 aSliceOfStrings3[3] = "d"
 aSliceOfStrings3[4] = "e"
 fmt.Println(aSliceOfStrings3[0])
 // This will print "a"


 // Append a Slice with more data
 aSliceOfStrings3 = append(aSliceOfStrings3, "f", "g", "h")
 fmt.Println(aSliceOfStrings3[6])
 // This will print "g"

 // Get the length and capacity of a Slice
 l := len(aSliceOfStrings3)
 fmt.Println("Length: ", l)
 // This will print "Length: 8"

 c := cap(aSliceOfStrings3)
 fmt.Println("Capacity: ", c)
 // This will print "Capacity: 10"

 // Copy an element of a Slice
 i := aSliceOfStrings3[1]
 fmt.Println(i)
 // This will print "b"


 // Copy part of a Slice in to another Slice, end needs to be what you want + 1 so if we want [2:4] we need to say [2:5]
 // You can also say [:] to mean the entire Slice. 
 // [:2] means the start of the Slice to the second element. 
 // And [2:] to mean from the second element to the end of the Slice.
 anotherSliceOfStrings1 := aSliceOfStrings3[2:5]
 fmt.Println("Length: ", len(anotherSliceOfStrings1))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings1))
 fmt.Println(anotherSliceOfStrings1[0])
 fmt.Println(anotherSliceOfStrings1[2])
 // This will print "Length: 3"
 // This will print "Capacity: 8" since we removed the first 2 elements of the original Slice
 // This will print "c" and "e"

 anotherSliceOfStrings2 := aSliceOfStrings3[:2]
 fmt.Println("Length: ", len(anotherSliceOfStrings2))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings2))
 fmt.Println(anotherSliceOfStrings2[0])
 fmt.Println(anotherSliceOfStrings2[1])
 // This will print "Length: 2"
 // This will print "Capacity: 10" the start of the Slice did not change so the capacity is the same
 // This will print "a" and "b" 

 anotherSliceOfStrings3 := aSliceOfStrings3[4:]
 fmt.Println("Length: ", len(anotherSliceOfStrings3))
 fmt.Println("Capacity: ", cap(anotherSliceOfStrings3))
 fmt.Println(anotherSliceOfStrings3[0])
 fmt.Println(anotherSliceOfStrings3[1])
 // This will print "Length: 4"
 // This will print "Capacity: 6" the start of the Slice changed so the capacity did as well
 // This will print "e" and "f"
}




Passing Slices to Functions
It's important to understand that even though a slice contains a pointer, it is really a value that under the covers is a struct value holding a pointer and a length. It is not a pointer to a struct. 

This matters when you pass a Slice to a function.  When you pass a Slice to a function you can modify the values in the Slice in the function and they will keep, however,  you can not modify the header (aka the length and capacity) as the header was passed by value not as a pointer.  If you want to modify the header, then you need to pass the Slice as a pointer not as a value.    You pass a Slice as a pointer by preceding it with an “&”.  Here is an example to replicate the "shift" function in Perl.

package main

import ("fmt")

var DEBUG int = 0

// This function tries to replicate the shift function in Perl by removing the first
// element of an slice and returning it
func Shift (pToSlice *[]string) string {
    sValue := (*pToSlice)[0]
    if DEBUG == 1 {
        fmt.Println("The slice before the shift: ",  *pToSlice)
    }
    *pToSlice = (*pToSlice)[1:len(*pToSlice)]
    
    if DEBUG == 1 {
        fmt.Println("The slice after the shift: ",  *pToSlice)
    }
    return sValue    
}


func main() {
    var a = []string{"1", "2", "3", "4"}
    for i := range a {
        fmt.Println(a[i])
    }
    // This will print 1, 2, 3, 4


    test := Shift(&a)
    fmt.Println("This is the shifted value: ", test)
    // This will print 1


    test2 := Shift(&a)
    fmt.Println("This is the shifted value: ", test2)
    // This will print 2
    
    for i := range a {
        fmt.Println(a[i])
    } 
    // This will print 3, 4
}




 

Wednesday, April 23, 2014

Creating Snapshots in Linux / MacOSX

Here is a script I wrote back in the 1999 time frame to perform daily, weekly, monthly snapshots of critical directories.  This scripts is designed for filesystems that support the notion of hard links, aka Linux and MacOSX. (The Windows filesystems do not support hard links and thus this will not work on Windows).

This script is usually called from /etc/crontab and requires that you have rsync installed on the system.  At the top of the actual script code is a section that you will need to update to specify where you want the backups to go and what directories you want to backup.



#!/usr/bin/perl
#
#
####################################################################
# Ideas taken from Mike's handy rotating-filesystem-snapshot       #
# utility, http://www.mikerubel.org/computers/rsync_snapshots/     #
# and from code written by Eric Ross                               #
####################################################################
#
####################################################################
# This program is not guaranteed to work at all, and by using this #
# program you release the author of any an all liability.          #
#                                                                  #
# You may use this program so long as this notice, disclaimer and  #
# comment box remain intact and unchanged.                         #
#                                                                  #
# Please send me all bugs and patches.                             #
#                                                                  #
# Written by Bret Jordan                                           #
# jordan at open1x littledot org                                   #
####################################################################
#
#
#
# Example /etc/crontab
# Every night at 1:01 make rsync copy and then give plenty of time before snapshots
# 01 1  * * *     root  /local/bin/snapshot rsync
#
# Every night at 2:01 make snapshots
# 01 2  * * *     root  /local/bin/snapshot snap 7 daily
#
# Every Sunday Morning at 3:01 make weekly snapshot
# 01 3  * * 7     root  /local/bin/snapshot snap 4 weekly
#
# First day of every month at 4:01 make monthly snapshot
# 01 4  1 * *     root  /local/bin/snapshot snap 12 monthly


use 5.8.8;
use strict;
use warnings;

our $VERSION = "0.02";
$VERSION = eval $VERSION;

my $sType = shift;
my $iHistoryLength = shift; 
my $sFreq = shift;


########################
# BEGIN THINGS TO UPDATE

my $sSnapDir = "/backups/snapshots";
my $sCurrentBackupDir = "$sSnapDir/backup.current";
my @aDirsToBackup = qw (/data/home/);

# END THIGNS TO UPDATE
########################


unless ($sType eq "rsync" || $sType eq "snap")
{ &ShowSyntax(); }


if ($sType eq "snap")
{
    unless ($iHistoryLength =~ /^\d+$/) 
    { &ShowSyntax(); }

    unless ($sFreq eq "hourly" || $sFreq eq "daily" || $sFreq eq "weekly" || $sFreq eq "monthly") 
    { &ShowSyntax(); }
}


sub ShowSyntax
{
    print "Please run command with ./snapshot <rsync snap=""> <historylength> <freq name="">\n";
    print "Example: ./snapshot 7 daily\n";
    print "Example: ./snapshot 24 hourly\n";
    die;
}

# Lets make sure we are running at root
unless ( $< == 0 ) { die "This program must be run as root\n"; }

# Do we have write access to the snap directory?
unless ( -w $sSnapDir ) { die "This user does not have write access to $sSnapDir\n"; }


if ($sType eq "rsync") 
{
    #----------------------------------------
    # Rsync Command
    #----------------------------------------
    #-a = archive mode which is -rlptgoD (no -H,-A,-X)
    #
    #-r = recurse in to directories
    #-l = copy symlinks as symlinks
    #-p = preserve permissions
    #-t = preserve modification times
    #-g = preserve group
    #-o = preserve owner
    #-D = preserve device files and special files

    foreach (@aDirsToBackup) { system("rsync -vax --delete $_ $sCurrentBackupDir"); }

    # Touch the directory so the date time is right
    system("touch $sCurrentBackupDir");
}
elsif ($sType eq "snap")
{
    # Step 1: Delete oldest snap shot and increase the age of the rest
    my $i = $iHistoryLength;
    while ($i > 0)
    {
    my $sCurrentDir = "$sSnapDir/backup.$sFreq.$i";

    # If index equals the max length of the history, then delete that directory
    if ( $i == $iHistoryLength ) { system ("rm -rf $sCurrentDir"); }
    else 
    {  
        my $j = $i + 1;
        my $sNewDir = "$sSnapDir/backup.$sFreq.$j";
        if ( -d $sCurrentDir ) { system ("mv $sCurrentDir $sNewDir"); }
    }
    $i--;
    }

    # Step 2: Make a hard link from the backup.current to backup.daily.1
    unless ( -d $sCurrentBackupDir ) { die "The current backup directory does not exist\n"; }
    system("cp -al $sSnapDir/backup.current $sSnapDir/backup.$sFreq.1");
}



Thursday, April 10, 2014

Heartbleed-ing on the inside

It is alarming to me how many vendors have not yet produced a patch for the OpenSSL issue, even days after it was released. Some vendors have taken the stance and said, "you should not have the management/configuration interface be public facing". This mindset follows the escargot model of security from the 1990s and is not an acceptable solution.

The idea of having just a hard and crunchy firewall perimeter while maintaining a soft and chewy inside is dangerous. Please remember that when a system in the organization is compromised, it can, and often does, give a remote user (threat actor) access to the inside network. When this happens the predictive and preventive security tools that you spent so much money on are not going to help you when all your trusted servers are effectively wide open to the internal network.

Thursday, February 6, 2014

Compile eepe r392 for MacOSX

Getting eepe to compile on a Mac is not too bad once you get everything in the right place. The versions of code I am running are as follows:
  • Mac OSX 10.7.5
  • xcode 4.2
  • Qt 4.8.2
I am going to assume you have some basic understanding of installing applications, downloading source code, and generally working with source code. Here are the steps:

Step 1: Install XCode if you have not already done so (you can get this from the App Store) and install Qt 4.8.x from http://qt-project.org/downloads.  5.x might work as well, but I have not tried that.

Step 2: Make a directory in your home directory for source code, I call mine "workspace"

Step 3: Download the missing qextserialenumerator_osx.cpp file from https://code.google.com/p/qextserialport/ .  I downloaded the following file: qextserialport-1.2rc.zip. Save this file to the workspace directory in your home directory

Step 4: Open a terminal
> cd workspace
> unzip qextserialport-1.2rc.zip

Step 5: Check out the eepe source code
> svn checkout http://eepe.googlecode.com/svn/trunk eepe

Step 6: Copy the missing files to the eepe source tree and build xcode project.  Unlike in Linux, qmake does not make a Makefile, but rather an xcode project.
> cp qextserialport-1.2rc/src/* eepe/src/
> cd eepe/src
> qmake

Step 7: From Finder open the following file "~/workspace/eepe/src/eepe.xcodeproj".  It should open in XCode if you have it installed correctly.  Now from the XCode menu select Product -> Archive.  This will build an archive version of the eepe code.

Step 8: After a few minutes the "Organizer" window should pop open and you should see your eepe project.  Control-Click and select "Show In Finder".  Then Control-Click the file "eepe 2-6-14 10.26 PM.xcarchive" (your file name will be slightly different based on date and time) and select "Show Package Contents".  Navigate down this tree to Products -> Applications and find the eepe.app.  Now drag this to your Desktop or the Applications directory and run the eepe.app

Saturday, December 21, 2013

Configuring VMware ESX 5.5 from the command line

Over the past few months I have spent a lot of time building a large ESX and nested ESX infrastructure based on VMware ESX 5.5. As you do this, you quickly realize that configuring ESX from the UI is painful, especially when you need to make sure you have all of the ESX servers exactly the same.  Here are some tips and tricks that I have found to be very helpful.

  1. Enable SSH on your ESX server and setup certificate based authentication.  This will greatly ease your work as you can then pipe configuration commands through SSH, which in turn allows you to script the whole configuration (and yes, this all works with the free version of ESXi).  I can now perform all of the configuration for 100+ ESX servers in a few seconds. On the ESX server the public keys for your Linux servers go in a file called:
    /etc/ssh/keys-root/authorized_keys
     
  2. I also like to change the motd, shell profile, and ntp.conf at the same time.  I just copy these files over.  The shell profile goes in a file called: /etc/profile.local

    My profile.local files looks like this:

    # profile.local

    PS1="[\u@\h]:\w-> "
    export PS1

    if [ "$TERM" != "dumb" ]; then
        alias ls='ls --color=auto'
        alias ll='ls -l -a --color=auto'
    fi

  3. Configure DNS and Hostname settings
    ssh root@x.x.x.x "esxcli network ip dns server add --server=192.168.0.11"
    ssh root@x.x.x.x "esxcli network ip dns server add --server=192.168.0.11"
    ssh root@x.x.x.x "esxcli system hostname set --host=esxserver01"
    ssh root@x.x.x.x "esxcli system hostname set --domain=mydomain.com"
     
  4. Configure NTP Settings
    Copy over a valid ntp.conf file to
    /etc/ntp.conf
    ssh root@x.x.x.x "esxcli network firewall ruleset set --enabled=true --ruleset-id=ntpClient"
    ssh root@x.x.x.x "chkconfig --add ntpd"
     
  5. License ESX
    ssh root@x.x.x.x "vim-cmd vimsvc/license --set xxxxx-xxxxx-xxxxx-xxxxx-xxxx"
     
  6. Setup any networking you need.  For my setup, I need to rename the first port group and create a new vswitch with a port group.  You also need to change the failover state as it defaults to non active.  This is how I did that.
    ssh root@x.x.x.x "esxcli network vswitch standard portgroup remove -p \'VM Network\' -v vSwitch0"
    ssh root@x.x.x.x "esxcli network vswitch standard portgroup add -p \'Trusted Network\' -v vSwitch0"
    ssh root@x.x.x.x "esxcli network vswitch standard add -v vSwitch1"
    ssh root@x.x.x.x "esxcli network vswitch standard portgroup add -p \'Client Network\' -v vSwitch1"
    ssh root@x.x.x.x "esxcli network vswitch standard uplink add -u vmnic1 -v vSwitch1"
    ssh root@x.x.x.x "esxcli network vswitch standard policy failover set -a vmnic1 -v vSwitch1"
     
  7. Reboot ESX server so all change take effect
    ssh root@x.x.x.x "reboot"
     
As you can see, once you setup certificate based authentication, you could easily script the above commands in bash, perl, python, etc and configure all of you ESX servers at once.  If you do this, I found that you need to add a sleep for 2 seconds statement between setting the DNS hostname and setting the DNS domain.