Thursday, December 29, 2011

OS X hidden folders, extended attributes, flags, and file ACLs

On lion the ~/Library directory is hidden by default in Finder. This doesn't bother me normally, since I rarely use Finder and it is visible on the commandline, but I recently got stuck needing to submit logs from ~/Library using a web-based form.

There are some one-off tricks you can use to access it, but, as far as I can see, no equivalent of the windows 'show hidden files' setting in Finder.

To see extended attributes (indicated by trailing @), file ACLs (indicated by trailing +), and flags, use this:
$ ls -l@eOd Library/
drwx------@ 38 user  group  hidden 1292 Dec 28 16:02 Library/
 com.apple.FinderInfo   32 
 0: group:everyone deny delete

You can manipulate the 'hidden' flag (which seems to actually be implemented as a FinderInfo attribute) and others with chflags:
chflags nohidden Library

Which gives:
$ ls -l@eOd Library/
drwx------+ 38 user  group  - 1292 Dec 28 16:02 Library/
 0: group:everyone deny delete

Tuesday, December 20, 2011

Simple cocoa dialogs for commandline tools in OS X

Got a commandline tool that needs to interact with a user? cocoaDialog is an app that can provide simple, good looking dialogs and can be invoked just by passing commandline options.

Sunday, December 18, 2011

NSA response to USB-borne malware

The Washington Post has an interesting article on the NSA's response to a USB-based malware infection on the US secret network in October 2008.

Wednesday, December 14, 2011

Ruby %x, system(), `backtick`, and puppet Facter::Util::Resolution.exec differences

Below are three different ways of running a system command from ruby:
irb(main):014:0> %x(echo "sdfsd")
=> "sdfsd\n"
irb(main):015:0> system('echo "sdfsd"')
sdfsd
=> true
irb(main):016:0> `echo "sdfsd"`
=> "sdfsd\n"
system() gives you a shell, but doesn't save the output. Backticks and %x are equivalent: they give you a shell environment and return the stdout output.

In puppet if you're using Resolution.exec:
Facter::Util::Resolution.exec('echo "sdfsd"')
Things are not so obvious. Depending on the puppet version, you might get a shell environment and puppet is also doing some checking with 'which' that might result in a 'nil' return if your command is not a simple binary.

Friday, December 9, 2011

Convert group and user GeneratedUIDs to human-readable form on OS X

When working with users and groups on OS X you frequently find that you need to lookup GUIDs to get their human-readable names. Here are a few examples of the fairly painful syntax (good candidates for bash aliases).

Get a group/user for a known GeneratedUID from local directory services:
dscl . -search /Users GeneratedUID 00052AE8-5000-6000-9007-666F6B666A66
dscl . -search /Groups GeneratedUID 00052AE8-5000-6000-9007-666F6B666A66

and from LDAP:
dscl /LDAPv3/ldap.company.com/ -search /Groups GeneratedUID 00052AE8-5000-6000-9007-666F6B666A66
dscl /LDAPv3/ldap.company.com/ -search /Users GeneratedUID 00052AE8-5000-6000-9007-666F6B666A66
ldapsearch -LLLx -b ou=group,dc=company,dc=com "apple-generateduid=00052AE8-5000-6000-9007-666F6B666A66" cn
ldapsearch -LLLx -b ou=people,dc=company,dc=com "apple-generateduid=00052AE8-5000-6000-9007-666F6B666A66" uid

Get a GeneratedUID for a known user/group:
dscl localhost -read /Search/Users/auser | grep -m1 GeneratedUID | cut -c15-
dscl localhost -read /Search/Groups/agroup | grep -m1 GeneratedUID | cut -c15-
ldapsearch -LLLx -b ou=group,dc=company,dc=com "cn=agroup" apple-generateduid
ldapsearch -LLLx -b ou=people,dc=company,dc=com "uid=auser" apple-generateduid

Ruby Time and DateTime: parse a string, compute the difference, simple right?

Time in ruby is a confusing maze of suckiness.

The Ruby Time class doesn't include a method to convert a string into a Time object (like the C standard 'strptime'), despite having a Time.strftime function. What the?

It turns out that Time.parse and Time.strptime do exist, but confusingly they aren't in the core class, but in a separate library you have to require that overrides the class. WTF?

irb(main):001:0> Time.parse
NoMethodError: undefined method `parse' for Time:Class
 from (irb):1
irb(main):002:0> require 'time'
=> true
irb(main):003:0> Time.parse
ArgumentError: wrong number of arguments (0 for 1)
 from (irb):3:in `parse'
 from (irb):3

So it seems that the best way to read a time from a file and compare it to the current time is the following, which gives you an answer in seconds:
irb(main):010:0> a=Time.parse('2011-01-10 12:34:00 UTC')
=> Mon Jan 10 12:34:00 UTC 2011
irb(main):012:0> b=Time.now.utc
=> Fri Dec 09 20:47:32 UTC 2011
irb(main):013:0> b-a
=> 28800812.788154

The only downside of this is that the library never fails, it tries really hard to give you a Time object back, to the point where it will just return the current time if the string is rubbish:
irb(main):027:0> Time.parse('asdfasdfas')
=> Fri Dec 09 14:02:40 -0800 2011

whereas DateTime is actually more sensible:
irb(main):028:0> DateTime.parse('asdfasdfas')
ArgumentError: invalid date
 from /usr/lib/ruby/1.8/date.rb:1576:in `new_by_frags'
 from /usr/lib/ruby/1.8/date.rb:1621:in `parse'
 from (irb):28
 from  :0

So my final solution was:
  begin
    DateTime.parse(time_string)
  rescue ArgumentError
    return 'UNKNOWN'
  end
  earlier = Time.parse(time_string)

  now = Time.now.utc
  hours = (now-earlier)/3600
  return hours
Read on for an attempt to do the same with DateTime, which is a terrible, terrible API.

DateTime has a simple way to ingest strings (and also has a strptime):
irb(main):015:0> require 'date'
=> false
irb(main):023:0> a=DateTime.parse('2011-12-09 00:00:00 UTC')
=> #
irb(main):024:0> puts a
2011-12-09T00:00:00+00:00
=> nil

But you can't take a difference between Time and DateTime:
irb(main):027:0> a=DateTime.parse('2011-12-01 00:00:00 UTC')
=> #
irb(main):028:0> b=Time.now
=> Fri Dec 09 12:10:40 -0800 2011
irb(main):029:0> b-a
TypeError: can't convert DateTime into Float
 from (irb):29:in `-'
 from (irb):29
 from  :0

Subtracting two DateTimes works but gives you an answer that is a rational number of days (?!):
irb(main):031:0> b-a
=> Rational(76394798789, 8640000000)
irb(main):032:0> c=b-a
=> Rational(76394798789, 8640000000)
irb(main):033:0> puts c
76394798789/8640000000
=> nil
irb(main):034:0> puts c.to_f
8.8419906005787
=> nil

Since a fractional number of days is pretty useless you can then convert this to an array of [hours,minutes,seconds,frac]:
irb(main):036:0> DateTime.day_fraction_to_time(c)
=> [212, 12, 27, Rational(98789, 8640000000)]

Why the subtraction doesn't return another type of time object is beyond me.

Wednesday, December 7, 2011

auditd on OS X

Auditd gets a limited description in the Snow Leopard Security Config doc. I'm posting a quick summary here, and will update it as I learn more.

auditd rules are kept in /etc/security.  The audit_control rules apply to all users and audit_user allows for per-user rules.

Audit logs are stored in binary format in /var/audit/logstarttime.logfinishtime and can be read with:
praudit /var/audit/20111018000205.20111018000916