2013-08-23

Exchange email support for Evolution on Ubuntu 13.04 Raring Ringtail

First, a little personal update: I have just left Wake Forest University, and joined Drexel University as a senior systems administrator in charge of the high performance computing University Research Computing Facility.

There are some dependencies which have not been properly encoded into the Exchange MAPI plugin for Evolution in Ubuntu 13.04. To get MAPI support, you must install: evolution-mapi and python-samba.

I was not able to get Exchange MAPI to work with Drexel's Exchange server: the issue was during the authentication step. However, using Exchange Web Services works. This uses Exchange's web service, which presents all the data in XML. To use this, the evolution-ews package has to be installed. Then, for the Host URL, use the usual web access address, appended with /EWS/Exchange.asmx So, if the webmail address is https://exchangeweb.myorganization.com/ the Host URL for Evolution will be https://exchangeweb.myorganization.com/EWS/Exchange.asmx

UPDATE: There is a bug in the exchange-ews package: there is an issue with sending mail. To fix, edit the the file in  ~/.config/evolution/mail/sources/  that contains a line that starts "Email=", and change it to Email=myemail@myorganization.com

2013-07-16

Backing out a Subversion Commit

A useful how-to from T. Kim Nguyen. I made a commit to my repository:
$ svn commit -m "changed something"
resulting in revision 989, and discovered it didn't work. D'oh!

To undo this commit, and go back to the state of the code in revision 988:
$ svn update
$ svn merge -c -989 https://svn.myserver.org/svn/myproject
$ svn stat
$ svn commit -m "undid the previous change"
This results in revision 990, but with the state of the code as in 988.

2013-04-11

rpmbuild, SPEC files, and prerequisites

At some point or other, you may try to build an RPM from a SPEC file and find that you are missing some dependencies:
$ rpmbuild -ba rt4.spec
error: Failed build dependencies:
        /usr/share/fonts/google-droid/DroidSansFallback.ttf is needed by rt4-4.0.8-0.20121228.0.el6.noarch
        /usr/share/fonts/google-droid/DroidSans.ttf is needed by rt4-4.0.8-0.20121228.0.el6.noarch
You may think (at least, I did) that all you need to do is to make sure those files exist. Unfortunately, no: you will need to install packages which provide those files (or capabilities, in the RPM jargon). In this case:

$ yum whatprovides /usr/share/fonts/google-droid/DroidSans.ttf
...
google-droid-sans-fonts-20100409-1.el6.noarch : A humanist sans serif typeface
Repo        : myownrepo-6-x86_64-server
Matched from:
Filename    : /usr/share/fonts/google-droid/DroidSans.ttf
If you look in the SPEC file:
Requires:  /usr/share/fonts/google-droid/DroidSansFallback.ttf
Requires:  /usr/share/fonts/google-droid/DroidSans.ttf
BuildRequires:  /usr/share/fonts/google-droid/DroidSansFallback.ttf
BuildRequires:  /usr/share/fonts/google-droid/DroidSans.ttf
As described in the link about capabilities above, those lines do not just specify package names but capabilities, which then mean that the package you are working on will require packages which provide the listed capabilities.

2013-04-08

Python tip - converting HH:MM:SS time into more understandable format

The Torque resource manager for clusters prints out amounts of time -- CPU time, or walltime -- in HH:MM:SS format. For small numbers, it's easy enough to understand: 04:00:00 = 4 hours. But for larger numbers, I wanted the time amount specified in days, hours, minutes, and seconds. Here's a quick way to do it using the datetime module. (I'm working with Python 2.6 here, which is what comes with RHEL6.) It uses a list comprehension to split up the HH:MM:SS time string. (BTW, I am using ipython as the interactive Python shell.)

In [4]: import re, datetime

In [5]: def timedeltastr(timestr):
   ...:     dayspat = re.compile(r'\ days?,')
   ...:     t = [int(i) for i in timestr.split(':')]
   ...:     td = datetime.timedelta(hours=t[0], minutes=t[1], seconds=t[2])
   ...:     return dayspat.sub('d', str(td))
   ...:
In [6]: timestr = '3400:00:00'

In [7]: timedeltastr(timestr)
Out[7]: '141d 16:00:00'

2013-04-05

Small Python tip - sorted iterating over dictionary

Python dictionaries are great. However, iterating over dictionaries results in an unsorted order:
In [1]: d = {'a':10, 'b': 20, 'c': 30}

In [2]: for key,value in d.iteritems():
   ...:     print key, value
   ...:
a 10
c 30
b 20
The fix is to use sorted():

In [3]: for key,value in sorted(d.iteritems()):
   ...:     print value
   ...:
a 10
b 20
c 30

2013-03-15

ntpdate service on Fedora 18 (Spherical Cow)

I had trouble getting ntp to sync time: starting the ntpdate service gave errors. Manually running ntpdate produced the error message "no server suitable for synchronization found". This answer at serverfault fixed it for me.

Made a change to /etc/sysconfig/ntpdate:

# Options for ntpdate
OPTIONS="-u -p 2"
# Number of retries before giving up
RETRIES=2
# Set to 'yes' to sync hw clock after successful ntpdate
SYNC_HWCLOCK=yes
Then, enable the service and start it:
$ sudo systemctl enable ntpdate.service
$ sudo systemctl start ntpdate.service
An annoyance: systemctl and sysctl are way too similar and do completely different things.

Writing a new SELinux policy module for a standard init daemon

This is going to be a summary of my experience writing new policy modules for Ganglia gmetad and gmond on RHEL5. Ganglia is a "scalable distributed monitoring system for high-performance computing systems." I downloaded the package source distribution, and built RPMs myself.

In case you are looking to apply this to something else, here are a couple of the underlying assumptions:
  • the service is a standard init-launched daemon
  • each service only has one executable, the daemon program
In the case of gmetad and gmond, the daemon programs are, respectively, /usr/sbin/gmetad and /usr/sbin/gmond.

I have written about creating new SELinux policies before, but I think this is better in that it wraps things up into a module that may be removed or updated more easily than a monolithic policy. Note, however, that rules governing network ports are not bundled into the module. (See below.)

This is going to be an iterative process. Before even starting, one needs to know which files/directories the daemons will write to, and if they run non-root. If the package one is working with is well-documented, this may be obtained from the documentation. If not, some trial and error will be needed. Also, for most programs, these file/directory locations are configurable.

We use the GUI Selinux Policy Generation tool, system-config-selinux. There is a good article on using this tool by Dan Walsh dating back to 2007.

We will start with gmetad. In the case of gmetad, the default location for the RRD files is /var/lib/ganglia/rrds. So, the policy should allow write access to /var/lib/ganglia.

In the Selinux Policy Generation tool, these are the entries used:
  • Name: gmetad
  • Executable: /usr/sbin/gmetad
  • Standard Init Daemon
  • Incoming network ports, both TCP and UDP: 8651,8652
  • Common Application Traits
    • Application uses syslog to log messages
    • Application uses /tmp to Create/Manipulate temporary files
    • Application uses nsswitch or translates UID's (daemons that run as non root)
  • Add Directory: /var/lib/ganglia
This generates 4 files in whatever directory you specify at the end of the druid: gmetad.fc, gmetad,if, gmetad.sh, gmetad.te. If you examine gmetad.sh, you will see:
#!/bin/sh
make -f /usr/share/selinux/devel/Makefile
/usr/sbin/semodule -i gmetad.pp

/sbin/restorecon -F -R -v /usr/sbin/gmetad
/sbin/restorecon -F -R -v /var/lib/ganglia
/usr/sbin/semanage port -a -t gmetad_port_t -p tcp 8651
/usr/sbin/semanage port -a -t gmetad_port_t -p tcp 8652
/usr/sbin/semanage port -a -t gmetad_port_t -p udp 8651
/usr/sbin/semanage port -a -t gmetad_port_t -p udp 8652
Note that the ports are not bundled into the "compiled" module file, gmetad.pp. The port rules are added "manually". The module merely defines the type gmetad_port_t.

The gmetad.te file is what we will be editing in the iterative steps below.  The first line determines a version number, that allows you to update a policy using "semodule -u gmetad.te".

policy_module(gmetad,1.0.0)

Make sure the gmetad service is not running. Now, turn off the auditd service, and move away the audit log file to simplify finding incremental changes in policy that are needed:
# service gmetad stop
# service auditd stop
# cd /var/log/audit< # mv audit.log audit.log.20130313-1500
Then, start up the audit daemon, followed by gmetad. Wait for a few minutes (or much longer) for gmetad to do its thing, and for auditd to accumulate all or most of the AVC denials that would affect gmetad. Once a sufficient amount of time has passed:
# grep gmetad /var/log/audit/audit.log | audit2allow -R > audit.out
The output should look like:
require {
        type gmetad_t;
        class capability { setuid setgid };
}

#============= gmetad_t ==============
allow gmetad_t self:capability { setuid setgid };
kernel_read_kernel_sysctls(gmetad_t)

Next, edit gmetad.te, and increment the version number. Append to the end of gmetad.te the contents of audit.out. Then, generate the policy file, and load the updated policy:
# make -f /usr/share/selinux/devel/Makefile
# semodule -u gmetad.pp
Next, shut down gmetad, shut down auditd, move the audit log away, start auditd, and start gmetad. Wait a bit, and look for new denials in the audit log by doing
# grep gmetad /var/log/audit/audit.log | audit2allow -R > audit2.out
To append any new rules, you have to manually pick out the new unique lines from audit2.out and put them in the appropriate sections (the 'require' section, or the block of allows) of gmetad.te. For gmetad.te, I found there wasn't much change between iterations. For gmond, however, there were quite a few, mostly the addition of file getattr permissions. This involved changing many lines like:

allow gmond_t lvm_t:file read;  -->  allow gmond_t lvm_t:file { getattr read };
This iteration may have to include alternating gmond and gmetad since gmetad has to connect to the gmond port, which means something like:
allow gmetad_t gmond_port_t:tcp_socket name_connect;

Here at the Wake Forest University HPC facility, we have a combination of cfengine and Puppet to manage machine configurations: cfengine for the RHEL5 nodes, and Puppet for the RHEL6 nodes. The policy .pp file is distributed via cfengine, and a shellcommand is run by cfengine to load/update the module, and additional commands do the file system relabelling and the port rules. Basically, reproducing the .sh file that the Policy Generation Tool creates.

UPDATE 2013-03-22: If you have a cyclic dependency in your policy modules -- in this case, gmond refers to gmetad, and gmetad refers to gmond -- you will find that you can't load the modules individually. All you have to do is load them all in one command line:
semodule -i gmond.pp gmetad.pp