Index:


System Administration

  • OS X: Making certain folders / files visible in the Finder

    There are some files and folders that OS X hides by default in the Finder. You can still get to them by chosing Go -> Go to Folder… and then typing the folder path (because Macs rule, Tab Completion works here!). You can also toggle all visibility on and off in the finder (see Showing all files in Finder), but sometimes you’d like a specific folder or file to be visible.

    SetFile to the rescue!

    From the man page:

    DESCRIPTION
    /usr/bin/SetFile is a tool to set the file attributes on files in an HFS+ directory. It attempts to be simi-
    lar to the setfile command in MPW. It can apply rules to more than one file with the options applying to all
    files listed.

    So, 

    sudo SetFile -a v /Volumes

    will make the /Volumes folder visible in the finder.

  • OS X: Showing or hiding all files in the Finder

    OS X / Mountain Lion hides a number of files from you, to help keep things tidier, and help make sure you don’t accidentally delete anything too important.  Most of the time this is useful, but sometimes it would be more convenient to be able to see all files.  

    The view all files Finder option can be change by setting the com.apple.finder option, called, unsurprisingly AppleShowAllFiles
    I have a short shell script:

    #!/bin/bash
    defaults write com.apple.finder AppleShowAllFiles TRUE
    killall Finder

    and to turn it off:

    #!/bin/bash
    defaults write com.apple.finder AppleShowAllFiles FALSE
    killall Finder

     
  • Making OS X Lion use search paths.

    Apple changed the behavior of DNS search list processing in Lion (OS X Lion: About search domains and name lookups). 

    This makes it differ from the behavior listed in RFC1536. If you need / prefer the RFC-compliant search path processing, add the -AlwaysAppendSearchDomains argument to the /usr/sbin/mDNSResponder process in /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist

    So:

                <key>ProgramArguments</key>
            <array>
                    <string>/usr/sbin/mDNSResponder</string>
                    <string>-launchd</string>
                    <string>-AlwaysAppendSearchDomains</string>
                    <string>-NoMulticastAdvertisements</string>
            </array>
    
  • Making DANE / TLSA records.

     Quick reminder for myself on how to generate / update TLSA records.

    ~/local/src/swede/swede/swede create --output rfc --usage 1 -s 0 -m 1 www.kumari.net
    No certificate specified on the commandline, attempting to retrieve it from the server www.kumari.net.
    Attempting to get certificate from 198.186.192.250
    M2Crypto does not support SNI: services using virtual-hosting will show the wrong certificate!
    Got a certificate with Subject: /serialNumber=l/YjABq5T5eemHk7J4kqJviHIR11OOkx/OU=GT03082892/OU=See www.rapidssl.com/resources/cps (c)13/OU=Domain Control Validated - RapidSSL(R)/CN=*.kumari.net
    _443._tcp.www.kumari.net. IN TLSA 1 0 1 8d930a464843e08660e3fd1ddce8ed4269cc0cd9cd53a8a306bce8abcf47aef5
    

     

    For the IETF one (tied to a CA)

    ~/local/src/swede/swede/swede create --output rfc --usage 0 -s 0 -m 1 -c ~/tmp/certs/starfield.crt www.ietf.org
  • Creating / renewing SSL Cert

    Generate the new key

    root@vimes:/etc/ssl# openssl genrsa -aes256 -out ./private/star.kumari.net-20110723.key 2048
     Generating RSA private key, 2048 bit long modulus
     ......................................................................................................+++
     .................................................................................................+++
     e is 65537 (0x10001)
     Enter pass phrase for ./private/star.kumari.net-20110723.key:
     Verifying - Enter pass phrase for ./private/star.kumari.net-20110723.key:
    

    Get the info from the old CSR

     root@vimes:/etc/ssl# openssl req -in star.kumari.net.csr -noout -text
     Certificate Request:
       Data:
           Version: 0 (0x0)
           Subject: C=US, ST=Virginia, L=Sterling, O=Warren Kumari, OU=Warren Kumari, CN=*.kumari.net/emailAddress=warrenkumari.net
           Subject Public Key Info:
               Public Key Algorithm: rsaEncryption
               RSA Public Key: (1024 bit)
                   Modulus (1024 bit):
                       00:a1:a1:f4:8a:50:e3:71:ee:4e:d2:3d:51:97:2c:
                       [SNIP]
    94:e9:1f:e7:07:e1:90:1e:ab Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha1WithRSAEncryption 71:b5:82:16:4f:7e:c9:f8:e9:3e:55:fe:86:d9:b9:e9:13:a2: [SNIP]
    23:7d:1f:68:38:5d:ca:12:f9:1e:44:3c:e4:47:a5:be:09:ac: 0b:6b

    Now generate a new CSR

     root@vimes:/etc/ssl# openssl req -new -key ./private/star.kumari.net-20110723.key -out star.kumari.net-20110723.csr
     Enter pass phrase for ./private/star.kumari.net-20110723.key:
     You are about to be asked to enter information that will be incorporated
     into your certificate request.
     What you are about to enter is what is called a Distinguished Name or a DN.
     There are quite a few fields but you can leave some blank
     For some fields there will be a default value,
     If you enter '.', the field will be left blank.
     -----
     Country Name (2 letter code) [US]:
     State or Province Name (full name) [Virginia]:
     Locality Name (eg, city) [Sterling]:
     Organization Name (eg, company) [Warren Kumari]:
     Organizational Unit Name (eg, section) [Warren Kumari]:
     Common Name (eg, YOUR name) [Warren Kumari]:*.kumari.net
     Email Address [warren.at.kumari.net]:
     Please enter the following 'extra' attributes
     to be sent with your certificate request
     A challenge password []:
     An optional company name []:
    
     root@vimes:/etc/ssl# ls
     certs  openssl.cnf  private  star.kumari.net-20110723.csr  star.kumari.net.csr  wildcard.kumari.net.csr  www.kumari.net_godaddy.csr
    

    And provide the CSR to the CA

     root@vimes:/etc/ssl# more star.kumari.net-20110723.csr 
     -----BEGIN CERTIFICATE REQUEST-----
     MIIC4jCCAcoCAQAwgZwxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTER
     MA8GA1UEBxMIU3RlcmxpbmcxFjAUBgNVBAoTDVdhcnJlbiBLdW1hcmkxFjAUBgNV
     [SNIP]
     e+WZXl16+MwNDk0tBQsOn2Z0ppC60O42wouMOIMJD904WS/72/NbDsxVmkmfig/Y
     UqrjcdnOXYfkzOfitv2TWlMwW7WtGQ==
     -----END CERTIFICATE REQUEST-----
    

     

    Installing / using the new certificate

    If you end up with a certificate that needs an intermediate certificate, there are a few options.

    Apache

    Apache knows how to deal with these using the SSLCACertificateFile option.

           # We want SSL for this site.
           SSLEngine On
           # Cert and key locations
           SSLCertificateFile /etc/ssl/certs/star.kumari.net-20110723.crt
           # Intermediate cert.
           SSLCACertificateFile /etc/ssl/certs/RapidSSL_CA_bundle.pem
           # And the key...
           SSLCertificateKeyFile /etc/ssl/private/star.kumari.net-20110723.key
    

    Postfix (and others)

    Some software doesn’t understand handing out intermediate CA certificates, but this can sometimes be worked around by putting both the certificate and the intermediate cert in one file.

    Create the combined pem file:

      $ cat star.kumari.net-20110723.pem RapidSSL_CA_bundle.pem > star.kumari.net-20110723-bundle.pem 
    

    Now tell Postfix about it:

     # TLS parameters
     smtpd_tls_cert_file=/etc/ssl/certs/star.kumari.net-20110723-bundle.pem 
     smtpd_tls_key_file=/etc/ssl/private/star.kumari.net-20110723.key
     smtpd_use_tls=yes
     smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
     smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

     

  • Mounting a QEMU Image

     

    Mounting a QEMU Image

    In order to mount a QUMU / KVM disk image you need to use qemu-nbd, which lets you use the NBD protocol to share the disk image on the network.

    First you need the module loaded:

     sudo modprobe nbd max_part=8
    

    Then you can share the disk on the network and create the device entries:

     sudo qemu-nbd --connect=/dev/nbd0 file.qcow2
    

    Then you mount it:

    sudo mount /dev/nbd0p1 /mnt/kvm
    

    When done, unmount and unshare it:

    sudo umount /mnt/kvm
    sudo nbd-client -d /dev/nbd0

     

  • Resetting DRAC4 cards.

    I recently donated a whole bunch of Dell server to ISC to help upgrade f.root-servers.net.

    They all had Dell DRAC4 cards in them and I wanted to reset them to a known config before donating them.

    Dell does provide some Linux software to talk to the cards, but is is mostly binary packages that run under RedHat Enterprise server or CentOS. Various folks have managed to make racadm and the other tools work under other distributions, but it is a headache to setup.

    I needed to wipe and stage 50 servers or so and I wanted to be able to do it in as simple a manner as possiable. I didn’t want to have to wipe the drives, install CentOS, wipe the DRAC card, then reinstall with the real OS, so I ended up writing the below code. It will talk to the DRAC card over the internal serial port and should run on any OS (including FreeBSD and netBSD) that run Python.

    #!/bin/python
    #
    # $Revision::                                              $
    # $Date::                                                  $
    # $Author::                                                $
    # Copyright: Warren Kumari (warren@kumari.net) --  2010
    #
    
    """
    This tries to connect to a DRAC4 card in a Dell server and 
    resets the password, IP, mask and gateway. 
    It assumes that the DRAC card will show up on /dev/ttyS1
    and that you have pySerial installed.
    
    It is neither pretty nor elegant, but I needed to reset the
    DRAC card on a bunch ofservers and this just works.
    It does no error checking, make completely brick your system, 
    may cuase early baldness, etc.
    
    Options:
      --ip: The IP address to set the DRAC to.
      --mask: The netmask (dotted quad).
      --gw: The gateway to use.
    
    Example:
      ./rac_reset.py --ip=192.168.0.12 --mask=255.255.255.0 --gw=192.168.0.1
    
     """
    import getopt
    import sys
    import time
    try:
      import serial
    except:
      print ('Unable to import pySerial module.\n'
             'On Ubuntu (and similar) you may be able to fix this with:\n'
             'apt-get install python-serial')
      sys.exit(-1)
    
    PORT = '/dev/ttyS1'
    FILTER=''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
    OK_STRING = '\x02\x60\x0A\x00\x00\x00\x00\x00\x00\x00\x96\x03'
    CALVIN_MD5 = 'e6e66b8981c1030d5650da159e79539a'
    
    def rac_connect():
      s = serial.Serial(PORT, timeout = 10)
      if s.isOpen():
        print 'Connected to: %s' % s.portstr
      else:
        print "Unable to open: %s", s.portstr
        sys.exit(-1)
      return s
        
    def xmit(str):
      s=rac_connect()
      print 'Going to send: %s' % str
      s.write(str)
      time.sleep(1)
      data = ''
      if s.inWaiting:
        data = data + s.read(s.inWaiting())
        time.sleep(0.5)
      while s.inWaiting():
        data = data + s.read(s.inWaiting())
        time.sleep(0.5)
      if data:
         if data == OK_STRING:
           print 'Success!'
         else:
           print "Got an error: %s\n" % dump(data, len(data))
      else:
        print 'Got no reply!'
      s.close()
      # And give the serial port a bit to settle down.
      time.sleep(2)
    
    def dump(src, length):
      """Prints the input in hex notation."""
      N=0; result=''
      while src:
        s,src = src[:length],src[length:]
        hexa = ' '.join(["%02X"%ord(x) for x in s])
        s = s.translate(FILTER)
        result += "%04X   %-*s   %s\n" % (N, length*3, hexa, s)
        N+=length
      return result
    
    def checksum(str):
      """Takes a string an calculates the RAC checksum.
    
      The RAC checksum seems to be made by adding all
      the charaters in the string mod 256 and then
      negating that..
    
      Args:
        str: A string that we want the checksum for.
    
      Returns: A char to be appended to the str to
               make the checksum correct.
      """
      a = 0
      for char in str:
        a = a + ord (char)
        a = a % 256
      checksum = 256 - a
      return chr(checksum)
    
    def make_str(command, cmd_no):
      """Returns a string suitable to be handed to the RAC.
    
      It looks like the DRAC expects a struct with various
      bits filled in with, um, something. This takes a
      command (like "racdump") and returns it embedded in
      the struct.
    
      Args:
        command: A string containing a command (e.g: "racdump")
        cmd_no : An integer, how many cammands we have run. It
          appears that the DRAC *may* uses this so that it can
          have multiple outstanding commands. Looks like not
          actually used.
      Returns:
        A string, suitable to be passed to the DRAC socket. Includes
        checksum."""
      PREFIX = "\2"
      PAD = "\0"
      SUFFIX = "\3"
      length = chr(len(command) + 6)
      command_str = ("P" + length + PAD + chr(cmd_no) + \
                     command + PAD)
      str  = (PREFIX + command_str)
      str = str + checksum(command_str) + SUFFIX
      return str
    
    def usage():
       print '%s' % __doc__
    
    if __name__ == "__main__":
      try:
        opts, args = getopt.getopt(sys.argv[1:], "hi:m:g:v", 
                                         ["help", "ip=", 'mask=', 'gw='])
      except getopt.GetoptError, err:
        print 'Option %s' % err
        sys.exit(2)
    
      verbose = False
      ip = ''
      mask = ''
      gw = ''
      for o, a in opts:
        if o == "-v":
          verbose = True
        elif o in ("-h", "--help"):
          usage()
          sys.exit()
        elif o in ("-i", "--ip"):
          ip = a
        elif o in ("-m", "--mask"):
          mask = a
        elif o in ("-g", "--gw"):
          gw = a
        else:
          assert False, "unhandled option"
    
      if not ip or not mask or not gw:
        print 'Error: must supply --ip, --mask and --gw!'
        sys.exit(-1)
      print 'Welcome to the RAC reset utility.'
      print 'This will reset the DRAC4 root password to "calvin",'
      print 'the IP to %s, the mask to %s and the gateway to %s\n' % (
          ip, mask, gw)
    #  ip = raw_input('Please enter IP: ')
    #  mask = raw_input('Please enter mask: ')
    #  gw = raw_input('Please enter gateway: ')
    
      cmd_no = 0
      xmit(make_str('setoid -g cfgUserAdmin -o cfgUserAdminPassword -i 1 %s' % CALVIN_MD5, cmd_no))
      xmit(make_str('setoid -g cfgLanNetworking -o cfgNicGateway %s' % gw.strip(),cmd_no))
      xmit(make_str('setoid -g cfgLanNetworking -o cfgNicNetmask %s' % mask.strip(),cmd_no))
      xmit(make_str('setoid -g cfgLanNetworking -o cfgNicIpAddress %s' % ip.strip(), cmd_no))
      print 'Done!'
    
      
    



    Here is a direct link: rac_reset.py

  • Creating a Xen image

    A friend of mine recently lost access to his server and so I figured I’d try and create him a virtual machine on one of my boxes while he was getting his back online.

    “No worries”, think I, “I’ll just install something like KVM and it’ll all be good”. Unfortunately I found out that the CPUs in my server (dual core P4 Xeon 3Ghz in a Dell 2850) don’t support the Intel-VT instruction set needed to run KVM. “Well, ok, I’ll just some something like ‘apt-get install ubuntu-xen-server’ and all will be good”…

     

    Unfortunately it turned out to be more complex than that — here is what I did to get it working, so next time I don’t waste 3 hours poking at this.

     

    The Intrepid xen packages install ‘xen-3.3.gz’ in /boot, but there are there is no kernel or modules file. Turns out the repository doesn’t have those, so you need to do:

    Kernel: http://packages.debian.org/lenny/i386/linux-image-2.6.26-2-xen-686/download

    Modules: http://packages.debian.org/lenny/i386/linux-modules-2.6.26-2-xen-686/download

    Then install using

    sudo dpkg -i linux-image-2.6.26-2-xen-686_2.6.26-15lenny2_i386.deb linux-modules-2.6.26-2-xen-686_2.6.26-15lenny2_i386.deb 

     

    After that I made the virtual machine and started it – “Hmmm, this is too easy…”, and sure enough, it was…

     

    Connecting to the virtual console only gave me:

    starting system log daemon: syslogd.
    Starting kernel log daemon: klogd.
    * Not starting internet superserver: no services enabled.
    Starting OpenBSD Secure Shell server: sshd[    8.032223] NET: Registered protocol family 10
    [    8.032777] lo: Disabled Privacy Extensions
    .
    Starting periodic command scheduler: crond.

     

    and then nothing — I figured I’d try and loging over ssh, but the install process hadn’t prompted me for a root password. I mounted the dis image and added a user, then tried logging in over ssh. Still no luch, I got:

     

    After much prodding I got everyting working correctly, here is how:

     

    The general config is in /etc/xen-tools/xen-tools.conf

    To create the image do:

     root@machine:/etc/xen-tools# sudo xen-create-image --hostname=xen1.example.com --ip xx.xx.xx.xx --ide --force --passwd --role udev
    General Information
    --------------------
    Hostname  : xen1.example.com
    Distribution  : lenny
    Partitions  : swap 128Mb (swap)
    / 4Gb (ext3)
    Image type  : sparse
    Memory size  : 128Mb
    Kernel path  : /boot/vmlinuz-2.6.26-2-xen-amd64
    Initrd path  : /boot/initrd.img-2.6.26-2-xen-amd64
    Networking Information
    ----------------------
    IP Address 1  : xx.xx.xx.xx [MAC: 00:16:3E:xx:xx:xx]
    Netmask  : xx.xx.xx.xx
    Gateway  : xx.xx.xx.xx
    Creating partition image: /home/xen/domains/xen1.example.com/swap.img
    Done
    Creating swap on /home/xen/domains/xen1.example.com/swap.img
    Don
    Creating partition image: /home/xen/domains/xen1.example.com/disk.img
    Done
    Creating ext3 filesystem on /home/xen/domains/xen1.example.com/disk.img
    Done
    Installation method: debootstrap
    ...

    To start the image, do:

     root@machine:/etc/xen-tools# sudo xm create /etc/xen/xen1.example.com.cfg

    To connect to the console, run

    xm console xen1.example.com

    . To disconnect the console, its ^-[ The config file for xen-tools is:

    /etc/xen-tools/xen-tools.conf
    dir = /home/xen
    ...
    #
    ##
    # Disk and Sizing options.
    ##
    #
    size = 4Gb # Disk image size.
    memory = 128Mb # Memory size
    swap = 128Mb # Swap size
    # noswap = 1 # Don't use swap at all for the new system.
    fs = ext3 # use the EXT3 filesystem for the disk image.
    dist = lenny # Default distribution to install.
    image = sparse # Specify sparse vs. full disk images.
    ...
    # Uncomment and adjust these network settings if you wish to give your
    # new instances static IP addresses.
    #
    netmask = xx.xx.xx.xx
    gateway = xx.xx.xx.xx
    ...
    #
    # Uncomment the following line if you wish to interactively setup
    # a new root password for images.
    #
    passwd = 1
    ...
    #
    # If you're using a newer version of the Xen guest kernel you will
    # need to make sure that you use 'xvc0' for the guest serial device,
    # and 'xvdX' instead of 'sdX' for serial devices.
    #
    # You may specify the things to use here:
    serial_device = hvc0

     

  • Restoring files with Amanda

    Amanda is a great backup system, although it tends to be a bit of a bandwidth hog — I use rsync over SSH for most daily backups, and then Amanda for full / weekly backups. 

    Go to the Amanda server and become root. Change to whatever directory you want the files restored to.

    root@ns03 amtest]# /usr/sbin/amrecover daily
    AMRECOVER Version 2.4.5. Contacting server on localhost ...
    220 ns03 AMANDA index server (2.4.5) ready.
    200 Access OK
    Setting restore date to today (2005-12-14)
    200 Working date set to 2005-12-14.
    Scanning /var/tmp...
    host_0: skipping cruft file, perhaps you should delete it.
    200 Config set to daily.
    501 Host ns03 is not in your disklist.
    Trying host ns03...
    200 Dump host set to <MACHINE>.
    Trying disk / ...
    Trying disk rootfs ...
    Can't determine disk and mount point from $CWD '/tmp/amtest'
    amrecover> sethost www.kumari.net
    200 Dump host set to www.kumari.net.
    amrecover> setdisk /home/wkumari
    200 Disk set to /home/wkumari.
    amrecover> ls
    <shows some files!>
    amrecover> add <files / directories, etc>
    amrecover> extract
    Extracting files using tape drive file:/amandatapes/daily on host localhost.
    The following tapes are needed: daily3
    Restoring files into directory /tmp/amtest
    Continue [?/Y/n]? y
    Extracting files using tape drive file:/amandatapes/daily on host localhost.
    Load tape daily3 now
    *** At this point, open another window,, and as user "amanda" do":
    amanda:$> /usr/sbin/amtape daily slot 3
    amtape: changed to slot 3 on file:/amandatapes/daily
    *** Go back to this window...
    Continue [?/Y/n/s/t]? y

    This can now also be done from the client end — just run amrecover from there.

    If you are using an encrypted backup, you will need to place the correct passphrase in /var/lib/amanda/.am_passphrase

  • Redirecting bash STDOUT, STDERR

    For some reason I can never remember this, so I have to store it for reference:

    Bash Redirect STDOUT and STDERR to /dev/null

    grep * &>/dev/null

     

    Bash Redirect STDERR to STDOUT

    This will cause the stderr output of a program to be written to the same file descriptor as stdout.

    grep * 2>&1