Some software I've found useful in my research, occasionally with personal forks, but no major time investments. When I've put in some more serious work, the appriopriate tag is code.
I spent some time today configuring Postfix so I could send mail
from home via SMTPS. Verizon, our ISP, blocks port 25 to
external domains, forcing all outgoing mail through their
outgoing.verizon.net
exchange server. In order to accept mail, they
also require you authenticate with your Verizon username and password,
so I wanted to use an encrypted connection.
For the purpose of this example, our Verizon username is jdoe
, our
Verizon password is YOURPASS
, you're running a local Postfix server
on mail.example.com
for your site at example.com
, and 12345
is a
free local port.
# cat /etc/postfix/main.cf
myhostname = mail.example.com
relayhost = [127.0.0.1]:12345
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/saslpass
sender_canonical_maps = hash:/etc/postfix/sender_canonical
# cat /etc/postfix/saslpass
[127.0.0.1]:12345 jdoe@verizon.net:YOURPASS
# postmap /etc/postfix/saslpass
# cat /etc/postfix/sender_canonical
root@mail.example.com jdoe@example.com
root@example.com jdoe@example.com
root@localhost jdoe@example.com
jdoe@mail.example.com jdoe@example.com
jdoe@localhost jdoe@example.com
# postmap /etc/postfix/sender_canonical
# cat /etc/stunnel/stunnel.conf
[smtp-tls-wrapper]
accept = 12345
client = yes
connect = outgoing.verizon.net:465
# /etc/init.d/stunnel restart
# postfix reload
Test with:
$ echo 'testing 1 2' | sendmail you@somewhere.com
Here's what's going on:
- You hand an outgoing message to your local Postfix, which decides to
send it via port
12345
on your localhost (127.0.0.1
) (relayhost
). - Stunnel picks up the connection from Postfix, encrypts everything,
and forwards the connection to port 465 on
outgoing.verizon.net
(stunnel.conf
). - Postfix identifies itself as
mail.example.com
(myhostname
), and authenticates using your Verizon credentials (smtp_sasl_…
). - Because Verizon is picky about the
From
addresses it will accept, we usesender_canonical
to map addresses to something simple that we've tested.
And that's it :p. If you're curious, there's more detail about all the Postfix config options in the postconf man page, and there's good SASL information in the SASL_README.
There's also a blog post by Tim White which I found useful. Because Verizon lacks STARTTLS support, his approach didn't work for me out of the box.
Verizon blocks outgoing connections on port 25 (SMTP) unless you
are connecting to their outgoing.verizon.net
message exchange
server. This server requires authentication with your Verzon
username/password before it will accept your mail. For the purpose of
this example, our Verizon username is jdoe
, our Verizon password is
YOURPASS
, and were sending email from me@example.com
to
you@target.edu
.
$ nc outgoing.verizon.net 25
220 vms173003pub.verizon.net -- Server ESMTP (...)
mail from: <jdoe@example.com>
550 5.7.1 Authentication Required
quit
221 2.3.0 Bye received. Goodbye.
Because authenticating over an unencrypted connection is a Bad Idea™,
I was looking for an encrypted way to send my outgoing email.
Unfortunately, Verizon's exchange server does not support STARTTLS
for encrypting connections to outgoing.verizon.net:25
:
$ nc outgoing.verizon.net 25
220 vms173003pub.verizon.net -- Server ESMTP (...)
ehlo example.com
250-vms173003pub.verizon.net
250-8BITMIME
250-PIPELINING
250-CHUNKING
250-DSN
250-ENHANCEDSTATUSCODES
250-HELP
250-XLOOP E9B7EB199A9B52CF7D936A4DD3199D6F
250-AUTH DIGEST-MD5 PLAIN LOGIN CRAM-MD5
250-AUTH=LOGIN PLAIN
250-ETRN
250-NO-SOLICITING
250 SIZE 20971520
starttls
533 5.7.1 STARTTLS command is not enabled.
quit
221 2.3.0 Bye received. Goodbye.
Verizon recommends pre-STARTTLS approach of wrapping the
whole SMTP connection in TLS (SMTPS), which it provides via
outgoing.verizon.net:465
:
$ python -c 'from base64 import *; print b64encode("\0jdoe@verizon.net\0YOURPASS")'
AGpkb2VAdmVyaXpvbi5uZXQAWU9VUlBBU1M=
$ openssl s_client -connect outgoing.verizon.net:465
...
220 vms173013pub.verizon.net -- Server ESMTP (...)
ehlo example.com
250-vms173013pub.verizon.net
250-8BITMIME
250-PIPELINING
250-CHUNKING
250-DSN
250-ENHANCEDSTATUSCODES
250-HELP
250-XLOOP 9380A5843FE933CF9BD037667F4C950D
250-AUTH DIGEST-MD5 PLAIN LOGIN CRAM-MD5
250-AUTH=LOGIN PLAIN
250-ETRN
250-NO-SOLICITING
250 SIZE 20971520
auth plain AGpkb2VAdmVyaXpvbi5uZXQAWU9VUlBBU1M
235 2.7.0 plain authentication successful.
mail from: <me@example.com>
250 2.5.0 Address Ok.
rcpt to: <you@target.edu>
250 2.1.5 you@target.edu OK.
data
354 Enter mail, end with a single ".".
From: Me <me@example.com>
To: You <you@target.edu>
Subject: testing
hello world
.
250 2.5.0 Ok, envelope id 4BHMFEZ7PHSETMT6@vms173013.mailsrvcs.net
quit
221 2.3.0 Bye received. Goodbye.
closed
This works, but with the rise of STARTTLS, getting your local Postfix mail server to support SMTPS requires a bit of fancyness with stunnel. The stunnel workaround is not too complicated, but I also wanted to look into the submission protocol (port 587), which adapts SMTP (designed for message transfer) into a similar protocol for message submission. Unfortunately, Verizon does not support STARTTLS here either.
$ nc outgoing.verizon.net 587
220 vms173005.mailsrvcs.net -- Server ESMTP (...)
ehlo example.com
250-vms173005.mailsrvcs.net
250-8BITMIME
250-PIPELINING
250-CHUNKING
250-DSN
250-ENHANCEDSTATUSCODES
250-EXPN
250-HELP
250-XADR
250-XSTA
250-XCIR
250-XGEN
250-XLOOP DA941C5B31BE4B102BB69B809BC66C4A
250-AUTH DIGEST-MD5 PLAIN LOGIN CRAM-MD5
250-AUTH=LOGIN PLAIN
250-NO-SOLICITING
250 SIZE 20971520
starttls
533 5.7.1 STARTTLS command is not enabled.
quit
221 2.3.0 Bye received. Goodbye.
In conclusion, Verizon supports a number of email submission standards, but the only secure approach is to use the outdated SMTPS. See my Postfix post for details on configuring Postfix to use Verizon's server for outgoing mail.
There are a number of good SMTP authentication tutorials out there. I
used John Simpson and Erwin Hoffmann's tutorials. For
cleaner examples of my testing tools (nc
and openssl s_client
),
see my simple servers post.
I was recently trying to add bookmarks to a PDF I'd generated with pdftk. It turns out to be fairly simple to add bookmarks to a PDF using Ghostscript, following maggoteer's post to the Ubunto forums. The syntax is:
$ gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=out.pdf in-*.pdf pdfmarks
Where out.pdf
is the generated PDF, in-*.pdf
are the input PDFs,
and pdfmarks
is a text file with contents like:
[/Title (Title Page) /Page 1 /OUT pdfmark
[/Title (Table of Contents) /Page 3 /OUT pdfmark
...
Nice and easy.
For nested levels, use the /Count
attribute. For example:
[/Count 3 /Title (Chapter 1) /Page 1 /OUT pdfmark
[/Count -2 /Title (Section 1.1) /Page 2 /OUT pdfmark
[/Title (Section 1.1.1) /Page 3 /OUT pdfmark
[/Title (Section 1.1.2) /Page 4 /OUT pdfmark
[/Count -1 /Title (Section 1.2) /Page 5 /OUT pdfmark
[/Title (Section 1.2.1) /Page 6 /OUT pdfmark
[/Title (Section 1.3) /Page 7 /OUT pdfmark
The argument to /Count
gives the number of immediately subordinate
bookmarks. The sign of the argument sets the default display
(negative for closed, positive for open).
You can also setup the document info dictionary with something like:
[ /Title (My Test Document)
/Author (John Doe)
/Subject (pdfmark 3.0)
/Keywords (pdfmark, example, test)
/DOCINFO pdfmark
If you want more detail, take a look at Adobe's pdfmark reference.
I've bundled the whole pdfmarks-generation bit into a script,
pdf-merge.py, which generates the pdfmark file and runs
Ghostscript automatically. Think of it as a bookmark-preserving
version of pdftk's cat
. The script uses pdftk internally to extract
bookmark information from the source PDFs.
The script also adds a bit of PostScript to ignore any bookmarks in
the source PDFs during the Ghostscript run. The only bookmarks in the
output will be the ones you specify explicitly in the pdfmarks file.
If for some reason the automatically generated pdfmarks are not quite
what you want, the script can pause (via --ask
) to allow you to
tweak the pdfmarks manually before running Ghostscript.
I've been streamlining my procedure for burning audio CDs, and I like what I've come up with. Unfortunately, I'll never remember it on my own, so here's a note to myself (any whoever else cares) on what to do.
First, build your playlist in MPD, using my one-liner to calculate the playlist duration (my CD-Rs hold 80 minutes). When you've got your playlist arranged to your satisfaction, convert the files to WAVs using:
$ i=1; for x in $(mpc -f '%file%' playlist); do j=$(seq -f '%02g' $i $i); let "i += 1"; flac -d --apply-replaygain-which-is-not-lossless=t -o $j.$(basename ${x/.flac/.wav}) /var/lib/mpd/music/$x; done
This assumes that all the files in your playlist are FLAC files, which is a good idea (disk space is cheap, FLAC is lossless with good open source support). It also assumes you've already stored ReplayGain settings in your FLAC files. If you haven't, you'll get warnings like:
WARNING: can't get track (or even album) ReplayGain tags
If that happens, go back and read about replay gain, add the tags, and try again ;).
See my replay gain post for more details on the
--apply-replaygain-which-is-not-lossless
option. After the decoding
step, you'll have a directory full of WAVs that have been normalized
to a standard track-level loudness. The bit about i
and j
ensures
that *.wav
will list the tracks in the order in which they appear in
your playlist. Then burn the tracks to a CD using
cdrecord:
$ cdrecord -v speed=1 dev=/dev/cdrom -eject -dao -audio -pad *.wav
If you don't care about the order, use $(ls *.wav | shuf)
instead of
*.wav
.
That's it! Audio CDs from MPD playlists in two lines.
The 2.X branch of GnuPG comes with gpg-agent for caching passphrases. The documentation is good, but here are my notes outlining my usual usage.
Add
if [ -f "${HOME}/.gnupg/agent-info" ]; then
source "${HOME}/.gnupg/agent-info"
fi
Start the agent with
$ GPG_TTY=$(tty)
$ gpg-agent --daemon --write-env-file "${HOME}/.gnupg/agent-info"
$ echo "GPG_TTY='${GPG_TTY}'; export GPG_TTY" >> "${HOME}/.gnupg/agent-info"
$ source "${HOME}/.gnupg/agent-info"
The GPG_TTY
bit will spawn the pinentry
call in the designated
TTY. This avoids troublesome issues like pinentry clobbering Mutt
if they are both using ncurses.
I didn't like any of the pinentry programs available on my system, so
I wrote my own: pinentry.py. To use my script, save it somewhere
on your system and add a line like the following to your
~/.gnupg/gpg-agent.conf
.
pinentry-program /path/to/pinentry.py
When you are done with the agent, kill it with
$ killall gpg-agent
$ rm -f "${HOME}/.gnupg/agent-info"
GnuTLS is the GNU SSL/TLS implementation, because OpenSSL's license is incompatible with the GPL. There are a number of small compatibility issues between the two, so it's best to use the OpenSSL tools to create certs and keys for use by OpenSSL-linked servers and the GnuTLS tools to create certs and keys for use by GnuTLS-linked servers. See X.509 certificates for details on creating self-signed keys with both packages.
I'm using LDAP (RFC 4510) to maintain a centralized address book at home. Here are my setup notes, mostly following Gentoo's LDAP howto.
Install OpenLDAP with the ldap
USE flag enabled:
# emerge -av openldap
If you get complaints about a cyrus-sasl
↔ openldap
dependency
cycle, you should temporarily (or permanently) disable the ldap
USE
flag for cyrus-sasl
:
# echo 'dev-libs/cyrus-sasl -ldap' > /etc/portage/package.use/ldap
# -ldap" emerge -av1 cyrus-sasl
# emerge -av openldap
Generate an administrative password:
$ slappasswd
New password:
Re-enter new password:
{SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
Configure the slapd
LDAP server. Here is a very minimal
configuration, read the OpenLDAP Admin Guide for details:
# emacs /etc/openldap/slapd.conf
# cat /etc/openldap/slapd.conf
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
database hdb
suffix "dc=example,dc=com"
checkpoint 32 30
rootdn "cn=Manager,dc=example,dc=com"
rootpw {SSHA}EzP6I82DZRnW+ou6lyiXHGxSpSOw2XO4
directory /var/lib/openldap-data
index objectClass eq
Note that inetorgperson is huge, but it's standardized. I think it's better to pick a big standard right off, than to outgrow something smaller and need to migrate.
Gentoo creates the default database directory for you, so you can ignore warnings about needing to create it yourself.
Configure LDAP client access. Again, read the docs for details on adapting this to your particular situation:
# emacs /etc/openldap/ldap.conf
$ cat /etc/openldap/ldap.conf
BASE dc=example,dc=com
URI ldap://ldapserver.example.com
You can edit '/etc/conf.d/slapd' if you want command line options
passed to slapd
when the service starts, but the defaults looked
fine to me.
Start slapd
:
# /etc/init.d/slapd start
Add it to your default runlevel:
# eselect rc add /etc/init.d/slapd default
Test the server with
$ ldapsearch -x -b '' -s base '(objectclass=*)'
Build a hierarchy in your database (this will depend on your organizational structure):
$ emacs /tmp/people.ldif
$ cat /tmp/people.ldif
version: 1
dn: dc=example, dc=com
objectClass: dcObject
objectClass: organization
o: Example, Inc.
dc: example
dn: ou=people, dc=example,dc=com
objectClass: organizationalUnit
ou: people
description: All people in organisation
dn: cn=Manager, dc=example,dc=com
objectClass: organizationalRole
cn: Manager
description: Directory Manager
$ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/people.ldif
$ rm /tmp/people.ldif
abook
If you currently keep your addresses in abook, you can export them to LDIF with:
$ abook --convert --infile ~/.abook/addressbook --outformat ldif \
| abook-ldif-cleanup.py --basedn 'ou=people,dc=example,dc=com' > dump.ldif
where abook-ldif-cleanup.py does some compatibility processing using the python-ldap module.
Add the people to your LDAP database:
$ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f dump.ldif
To check if that worked, you can list all the entries in your database:
$ ldapsearch -x -b 'dc=example,dc=com' '(objectclass=*)'
Then remove the temporary files:
$ rm -rf dump.ldif
Aliases
Ok, we've put lots of people into the people
OU, but what if we want
to assign them to another department? We can use aliases (RFC
4512), the symlinks of the LDAP world. To see how this
works, lets create a test OU to play with:
$ emacs /tmp/test.ldif
$ cat /tmp/test.ldif
version: 1
dn: ou=test, dc=example,dc=com
objectClass: organizationalUnit
ou: testing
$ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/test.ldif
$ rm /tmp/test.ldif
Now assign one of your people to that group:
$ emacs /tmp/alias.ldif
$ cat /tmp/alias.ldif
version: 1
dn: cn=Jane Doe, ou=test,dc=example,dc=com
objectClass: alias
aliasedObjectName: cn=Jane Doe, ou=people,dc=example,dc=com
$ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
$ rm /tmp/alias.ldif
The extensibleObject
class allows us to add the DN field, without it
you get:
$ ldapadd -D "cn=Manager,dc=example,dc=com" -xW -f /tmp/alias.ldif
Enter LDAP Password:
adding new entry "cn=Jane Doe, ou=test,dc=example,dc=com"
ldap_add: Object class violation (65)
additional info: attribute 'cn' not allowed
You can search for all entries (including aliases) with
$ ldapsearch -x -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
...
dn: cn=Jane Doe,ou=test,dc=example,dc=com
objectClass: alias
objectClass: extensibleObject
aliasedObjectName:: Y249TWljaGVsIFZhbGxpw6hyZXMsb3U9cGVvcGxlLGRjPXRyZW1pbHksZGM9dXM=
...
You can control dereferencing with the -a
option:
$ ldapsearch -x -a always -b 'ou=test, dc=example,dc=com' '(objectclass=*)'
...
dn: cn=Jane Doe,ou=people,dc=example,dc=com
cn: Jane Doe
sn: Doe
...
Once you've played around, you can remove the test
OU and its
descendants:
$ ldapdelete -D "cn=Manager,dc=example,dc=com" -xW -r ou=test,dc=example,dc=com
shelldap
There are a number of tools to make it easier to manage LDAP databases. Command line junkies will probably like shelldap:
$ shelldap --server ldapserver.example.com
~ > ls
cn=Manager
ou=people
~ > cat cn=Manager
dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
cn: Manager
~ > cd ou=people
ou=people,~ > ls
Shelldap's edit
command spawns your EDITOR
on a temporary file
populated by the entry you're editing. You can either alter the entry
as you see fit, or try something fancier in LDIF.
Mutt
If you use the Mutt email client (or just want a simple way to
query email addresses from the command line) there are a number of
scripts available. Pick whichever sounds most appealing to
you. I wrote up mutt-ldap.py, which lets you configuration the
connection details via a config file (~/.mutt-ldap.rc
) rather than
editing the script itself. Usage details are available in the
docstring.
Apple Address Book
You can configure Apple's Address Book to search an LDAP directory. See Humanizing OS X for details.
SSL/TLS
It took me a bit of work to get SSL/TLS working with my
GnuTLS-linked OpenLDAP. First, you'll probably need to generate
new SSL/TLS keys (/etc/openldap/ssl/*
) with certtool (see
X.509 certificates). Then add the following lines to
/etc/openldap/slapd.conf
:
TLSCipherSuite NORMAL
TLSCACertificateFile /etc/openldap/ssl/ca.crt
TLSCertificateFile /etc/openldap/ssl/ldap.crt
TLSCertificateKeyFile /etc/openldap/ssl/ldap.key
TLSVerifyClient never
Where ca.crt
, ldap.crt
, and ldap.key
are your new CA,
certificate, and private key. If you want to disable unencrypted
connections completely, remove the ldap://
entry from your slapd
command line by editing (on Gentoo) /etc/conf.d/slapd
so it has
OPTS="-h 'ldaps:// ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock'"
Now you should be able to restart slapd
so it will use the new
configuration.
Have clients running on your server use the local socket by editing
/etc/openldap/ldap.conf
to set:
URI ldapi://%2fvar%2frun%2fopenldap%2fslapd.sock
Test your server setup by running (on the server)
$ ldapsearch -x -b '' -s base '(objectclass=*)'
Copy your CA over to any client machines (I put it in
/etc/openldap/ssl/ldapserver.crt
), and set them up with the
following two lines in /etc/openldap/ldap.conf
:
URI ldaps://ldapserver.example.com
TLS_CACERT /etc/openldap/ssl/ldapserver.crt
Test your client setup by running (on the client)
$ ldapsearch -x -b '' -s base '(objectclass=*)'
You can configure shelldap
with the following lines in
~/.shelldap.rc
:
server: ldaps://ldapserver.example.com
tls: yes
tls_cacert: /etc/openldap/ssl/ldapserver.crt
You can configure mutt-ldap.py
with the following lines in
~/.mutt-ldap.rc
:
port = 636
ssl = yes
Debian-based systems
I wanted to mirror my home LDAP info on my public Ubuntu server. Here's a quick rundown of the Ubuntu setup. Install OpenLDAP:
$ sudo apt-get install slapd ldap-utils
Don't serve in the clear:
$ cat /etc/default/slapd
...
SLAPD_SERVICES="ldaps:/// ldapi:///"
...
Avoid Unrecognized database type (hdb)
by loading the hdb
backend
module before declaring hdb
databases:
$ sudo cat /etc/ldap/slapd.conf
...
moduleload back_hdb
database hdb
...
Convert the old school slapd.conf
to the new slapd.d:
$ sudo mv slapd.d{,.bak}
$ sudo mkdir slapd.d
$ sudo slaptest -f slapd.conf -F slapd.d
...
hdb_db_open: database "dc=example,dc=com": db_open(/var/lib/slapd/id2entry.bdb) failed: No such file or directory (2).
...
slap_startup failed (test would succeed using the -u switch)
...
$ sudo chown -R openldap.openldap slapd.d
Don't worry about that db_open
error, the conversion to slapd.d
will have completed successfully.
Set permissions on the database directory (note that the databases
should be under /var/lib/ldap
to match Ubuntu's default apparmor
config. Otherwise you'll see invalid path: Permission denied
errors
when slapd
tries to initialize the databaes).
$ sudo chown openldap.openldap /var/lib/ldap/
$ sudo chmod 750 /var/lib/ldap/
Configure your clients
$ cat /etc/ldap/ldap.conf
BASE dc=example,dc=com
URI ldaps://example.com
TLS_CACERT /etc/ldap/ssl/ldapserver.crt
Start slapd
and add it to your default runlevel:
$ sudo /etc/init.d/slapd start
$ sudo update-rc.d slapd defaults
Finally, import your directory data. Dump the data on your master server:
master$ sudo slapcat -b 'dc=example,dc=com' > database.ldif
Load the data on your slave:
$ sudo /etc/init.d/slapd stop
$ sudo slapadd -l database.ldif
$ sudo /etc/init.d/slapd start
References
There's a good overview of schema and objectclasses by Brian Jones on O'Reilly. If you want to use inetOrgPerson but also include the countryName attribute, ...
Over the years I've watched Kerberos and related tools from afar, interested in the idea, but not interested enough to figure out the installation, configuration, etc. Well, in an attempt to secure assorted NFS mounts around my home, I decided to take the plunge today and install NFSv4 + Kerberos. Here are my notes for my Gentoo systems, mostly following the Kerberos install guide. I'll use the following settings for my examples:
- Domain:
d.net
- Kerberos realm:
R.EDU
- Server:
server.d.net
- Client:
client.d.net
- User:
jdoe
(on both the client and server)
Setup the Kerberos server
Emerge the Kerberos server (app-crypt/mit-krb5
) and PAM module:
# USE=-openldap emerge -av pam_krb5
-openldap
breaks an OpenLDAP <-> Kerberos dependency loop.
Setup DNS to centralize service location management (krb manual):
# emacs /etc/bind/pri/d.net.zone
# /etc/init.d/named restart
I added the following entries to the $ORIGIN d.net.
section of my
zone file:
_kerberos TXT "R.EDU"
kerberos A 192.168.0.2
krb5 A 192.168.0.2
_kerberos-adm._tcp SRV 0 0 749 krb5
_kerberos._udp SRV 0 0 88 krb5
_kerberos-master._udp SRV 0 0 88 krb5
_kpasswd._udp SRV 0 0 464 krb5
Configure Kerberos and the KDC (krb manual):
# cp /etc/krb5.conf{.example,}
# emacs /etc/krb5.conf
# cat /etc/krb5.conf
[libdefaults]
default_realm = R.EDU
dns_fallback = yes
kdc_ports = 88
[realms]
R.EDU = {
kdc = "server.d.net" # HACK?
admin_server = "server.d.net" # DNS support not yet complete
}
[domain_realm]
.d.net = R.EDU
d.net = R.EDU
[logging]
kdc = FILE:/var/log/krb5/kdc.log
admin_server = FILE:/var/log/krb5/kadmind.log
default = FILE:/var/log/krb5/krblib.log
# cp /var/lib/krb5kdc/kdc.conf{.example,}
# emacs /var/lib/krb5kdc/kdc.conf
# cat /var/lib/krb5kdc/kdc.conf
[realms]
R.EDU = {
admin_server = server.d.net # DNS support not yet complete
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5.keytab
acl_file = /var/lib/krb5kdc/kadm5.acl
key_stash_file = /var/lib/krb5kdc/.k5.R.EDU
kdc_ports = 88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
}
Create the database and stash file (krb manual):
# kdb5_util create -r R.EDU -s
Add administrators to the access control list (krb manual):
# emacs /var/lib/krb5kdc/kadm5.acl
# cat /var/lib/krb5kdc/kadm5.acl
jdoe/admin@R.EDU x
# kadmin.local
kadmin.local: add_principal jdoe/admin@R.EDU
WARNING: no policy specified for jdoe/admin@R.EDU; defaulting to no policy
Enter password for principal "jdoe/admin@R.EDU":
Re-enter password for principal "jdoe/admin@R.EDU":
Principal "jdoe/admin@R.EDU" created.
kadmin.local: quit
Start the Kerberos daemons:
# /etc/init.d/mit-krb5kdc start
# /etc/init.d/mit-krb5kadmind start
Add them to your default runlevel with:
# eselect rc add /etc/init.d/mit-krb5kadmin default
# eselect rc add /etc/init.d/mit-krb5kadmind default
Add new principals (krb manual):
$ kadmin -p jdoe/admin
Authenticating as principal jdoe/admin with password.
Password for jdoe/admin@R.EDU:
kadmin: list_principals
...
kadmin: add_principal jdoe
WARNING: no policy specified for jdoe@R.EDU; defaulting to no policy
Enter password for principal "jdoe@R.EDU":
Re-enter password for principal "jdoe@R.EDU":
Principal "jdoe@R.EDU" created.
kadmin: quit
Now you can get your ticket granting ticket (TGT) with
$ kinit
and do all the other standard Kerberos stuff.
Setup the Kerberos client
Not much to do here, just
# emerge -av pam_krb5
and scp
/etc/krb5.conf
from your Kerberos server onto the client.
Check that everything works by running
$ kinit
Password for jdoe@R.EDU:
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: jdoe@R.EDU
Valid starting Expires Service principal
06/02/11 10:32:30 06/02/11 20:32:30 krbtgt/R.EDU@R.EDU
renew until 06/03/11 10:32:30
Setup the NFS server
Now we'll setup NFSv4 using Kerberos authentication. There don't seem to be authoritative docs, but there are a number of good tutorials (1, 2, 3, 4).
Emerge nfs-utils
with the kerberos
USE flag set
(homepage). You may also want app-crypt/kstart
(homepage) to automatically renew your server and client
tickets. Now is also a good time to check your kernel config. I was
missing CRYPTO_CTS, which lead to
error writing to downcall channel /proc/net/rpc/auth.rpcsec.context/channel: Invalid argument
If your realm is not your uppercased domain name, you probably also want a version of libnfsidmap >0.21 to avoid the
get_ids: failed to map name 'nfs/<fqdn>@REALM' to uid/gid: Invalid argument
bug (discussion).
Since we'll be running the NFS service, we'll need a
nfs/<fqdn>@REALM
principal for the service. Because we want that
service to start automatically at boot, we neek to keep its key in a
keytab file (krb manual).
# kadmin.local -p jdoe/admin
Authenticating as principal jdoe/admin with password.
Password for jdoe/admin@R.EDU:
kadmin.local: add_principal -randkey nfs/server.d.net
WARNING: no policy specified for nfs/server.d.net@R.EDU; defaulting to no policy
Principal "dns/server.d.net@R.EDU" created.
kadmin.local: ktadd nfs/server.d.net
Entry for principal nfs/server.d.net...
...
kadmin.local: quit
You need use kadmin.local
here (instead of kadmin
) so the process
has premission to create and edit the keytab file.
Read through /etc/idmapd.conf
to see if you need to make any changes
for your setup. I set Domain = d.net
and Local-Realms = R.EDU
.
You probably also want to look through /etc/conf.d/nfs
. I added
-vvv
to OPTS_RPC_GSSD
, OPTS_RPC_IDMAPD
, and OPTS_RPC_SVCGSSD
to aid in debugging.
Setup your export filesystem. NFSv4 wants all its exports to live under a single root, so do something like:
# mkdir /export
# mkdir /export/home
# mount --bind /home /export/home
And then setup /etc/exports
:
# cat /etc/exports
/export *(rw,fsid=0,insecure,sec=krb5p,root_squash,no_subtree_check,crossmnt)
/export/a/ *(rw,insecure,sec=krb5p,root_squash,no_subtree_check)
Note that the syntax has changed somewhat, and there seem to have been
a few versions of the NFSv4 syntax. exports(5)
should contain good
documentation for whatever version of nfs-utils
you have installed
on your system.
If you used mount --bind
to populate /export
, make sure you add
appropriate entries to /etc/fstab
so the mounts come up when you
reboot.
# cat /etc/fstab
...
/home /export/home none rw,bind 0 0
Start the NFS server:
# /etc/init.d/nfs start
Add it to your default runlevel with:
# eselect rc add /etc/init.d/nfs default
Setup the NFS client
In order to use private (sec=krb5p
) mounts, you'll need to enable
RPCSEC_GSS_KRB5. Without it, you'll get error
messages such as
gss_create: Pseudoflavor 390005 not found!
You'll also need nfs-utils
here
# USE="kerberos" emerge -av nfs-utils
You'll need a client principal for secured mounts, so head back over to the server and run
server.d.net# kadmin.local
kadmin.local: add_principal -randkey nfs/client.d.net
kadmin.local: ktadd -k /tmp/krb5.keytab nfs/client.d.net
Entry for principal nfs/client.d.net ...
...
kadmin.local: quit
Then scp
the new keyfile over to /etc/krb5.keytab
on the client
and remove the temporary version from the host. You can list the keys
in a keytab with klist -e -k /path/to/keytab
if you find a keytab
lying around but forget what's inside it.
On the client, you'll need gssd
and idmapd
running (both part of
nfs-utils
).
# /etc/init.d/rpc.gssd start
# /etc/init.d/rpc.idmapd start
There's no need to add these to your default runlevel, since they
should be started automatically if you have NFSv4 entries in your
/etc/fstab
(I have no idea how that works).
Now test your mount:
$ sudo mkdir /tmp/mnt
$ sudo mount -v -t nfs4 -o sec=krb5p server:/ /tmp/mnt
mount.nfs4: timeout set for Thu Jun 2 10:44:46 2011
mount.nfs4: trying text-based options '...'
server:/ on /tmp/mnt type nfs4 (rw,sec=krb5p)
$ ls /tmp/mnt
ls: cannot access /tmp/mnt: Permission denied
$ klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1000)
$ kinit
Password for jdoe@R.EDU:
$ ls /tmp/mnt/
home
Note that if you kestroy
your key, you can still access the files:
$ kdestroy
$ klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1000)
$ ls /tmp/mnt/
home
This is because your credentials have been cached in the client's kernel. On AIX there seems to be an nfsauthreset command to manually flush cached GSSAPI information. Linux support is waiting on a new key ring implementation.
Other stuff
If you hadn't had the kerberos
USE flag set before, you should
consider adding it to your /etc/make.conf
and running
$ sudo emerge -av --deep --newuse --update @world
to get Kerberized versions of any packages you have installed
(e.g. cups
, curl
, cvs
, emacs
, openssh
, most SASL libraries,
...).
For details on using Kerberos with SSH, check out the excellent
description in the SSH definative guide. The key elements are
host/<fqdn>@REALM
principals for each host (with keyfiles on each
server) and appropriate enabling of the GSSAPI*
options in
sshd_config
and ssh_config
.
There's also suite of Kerberos-aware utilities in
app-crypt/mit-krb5-appl
(krcp
, krlogin
, krsh
, ktelnet
, and
kftp
). I don't use the non-Kerberized versions, so I haven't tried
any of these.
If you're using MPD on an NFS-mounted music repository, you might
be interested in my kinit-mpd.sh script for granting the mpd
user access to the NFS-mounted music as the nobody
principal.
OpenSSH stores lists of SSH public keys in known_hosts
files, so it can verify that the host you're logging into is the host
you expect and not a man-in-the-middle attacker. To reduce the risk
of island-hopping attacks, OpenSSH has a HashKnownHosts yes
option to store HMAC-SHA1 encrypted versions of host names and
IPs in your known_hosts
files rather than the clear text. This
makes it harder for an attacker to use the information stored in your
known_hosts
. However, it also makes it harder for you to use that
information.
I was digging through my known_hosts
file yesterday compiling a list
of servers where I have login accounts. I keep better track of these
things recently (using GPG to symmetrically encrypt the list),
but my known_hosts
file predates my quality-accounting phase.
Anyhow, I wrote up some simple tools to make reverse-engineering a
known_hosts
file a bit less painful.
You can use your monkeysphere keyring to see if you recognize any of the public keys. This avoids having to deal with the hashed names at all, but assumes none of your servers are sharing keys. unhash-known-hosts.sh automates this:
$ unhash-known-hosts.sh path/to/known_hosts
GnuPG ID 01234567 (ssh://server.example.net) matches |1|Bvjsg3lqJJ/M9rTYz1HfY+T/RoM=|DhZlGg3GFMWtVcjz4LNfJ8afi7w=
did not match |1|vug6FlX6GCaIIzkv3wS3zftQyyw=|PdMYEIaWTzHCv/4ZhNiR2DD6E0A=
...
Once you've got the low-hanging fruit out of the way, you can get a list of the high-hanging fruit:
$ unhash-known-hosts.sh path/to/known_hosts | sed -n 's/^did not match //p' > unknown_hosts
Start guessing with crack known hosts.py! IPs are usually a
good starting point, because any host in your known_hosts
file must
have an entry for its IP.
$ crack_known_hosts.py --known-hosts unknown_hosts --ip 192.168.*.*
You can also run a full scan of alphanumeric entries up to a specified length (this gets slow quickly, which is, after all, why you hashed the entries in the fiest place).
$ crack_known_hosts.py --known-hosts unknown_hosts --alphanum 16
Removing entries from unknown_hosts
as you crack them will make
future crack_known_hosts.py
attempts on that file faster.
Once you've cracked one name, you can use unique known hosts.py to find other entries that share the same key.
$ unique_known_hosts.py path/to/known_hosts
And there you have it. Happy cracking! ;).
Tor is an anonomizing proxy, see their list of usage
scenarios if you want more details. A basic Tor client is
extremely easy to set up on Gentoo, just emerge net-misc/tor
,
possibly tweak the stock /etc/tor/torrc
, and fire up the connection
with
$ sudo /etc/init/tor start
which (by default) opens a SOCKS
To use your new Tor "proxy" with Firefox, go to
Edit->Preferences->Advanced->Network->Connection->Settings->Manual
proxy configuration
and set
SOCKS host: localhost
Port: 9050
Version: SOCKSv5
To use remote DNS, enter about:config
in the address bar, set the
filter to dns
, and set network.proxy.socks_remote_dns
to true
by
double clicking.
To disable cookies, which would allow the sites you're connecting to
to track you as your exit IP changes, go to
Edit->Preferences->Privacy
, select Firefox will: Use custom
settings for history
, and make sure Accept cookies from sites
is
unchecked.
To check that everything is properly configured, you can browse over to Tor's check utility.