Add auth.gssapi option to mutt-ldap.py (for use with Kerberos).
[mutt-ldap.git] / mutt-ldap.py
1 #!/usr/bin/env python
2 #
3 # Copyright (C) 2008-2011  W. Trevor King
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 """LDAP address searches for Mutt.
19
20 Add :file:`mutt-ldap.py` to your ``PATH`` and add the following line
21 to your :file:`.muttrc`::
22
23   set query_command = "mutt-ldap.py '%s'"
24
25 Search for addresses with `^t`, optionally after typing part of the
26 name.  Configure your connection by creating :file:`~/.mutt-ldap.py`
27 contaning something like::
28
29   [connection]
30   server = myserver.example.net
31   basedn = ou=people,dc=example,dc=net
32
33 See the `CONFIG` options for other available settings.
34 """
35
36 import email.utils
37 import itertools
38 import os.path
39 import ConfigParser
40
41 import ldap
42 import ldap.sasl
43
44
45 CONFIG = ConfigParser.SafeConfigParser()
46 CONFIG.add_section('connection')
47 CONFIG.set('connection', 'server', 'domaincontroller.yourdomain.com')
48 CONFIG.set('connection', 'port', '389')  # set to 636 for default over SSL
49 CONFIG.set('connection', 'ssl', 'no')
50 CONFIG.set('connection', 'basedn', 'ou=x co.,dc=example,dc=net')
51 CONFIG.add_section('auth')
52 CONFIG.set('auth', 'user', '')
53 CONFIG.set('auth', 'password', '')
54 CONFIG.set('auth', 'gssapi', 'no')
55 CONFIG.read(os.path.expanduser('~/.mutt-ldap.rc'))
56
57 def connect():
58     protocol = 'ldap'
59     if CONFIG.getboolean('connection', 'ssl'):
60         protocol = 'ldaps'
61     url = '%s://%s:%s' % (
62         protocol,
63         CONFIG.get('connection', 'server'),
64         CONFIG.get('connection', 'port'))
65     connection = ldap.initialize(url)
66     if CONFIG.getboolean('auth', 'gssapi'):
67         sasl = ldap.sasl.gssapi()
68         connection.sasl_interactive_bind_s('', sasl)
69     else:
70         connection.bind(
71             CONFIG.get('auth', 'user'),
72             CONFIG.get('auth', 'password'),
73             ldap.AUTH_SIMPLE)
74     return connection
75
76 def search(query, connection=None):
77     local_connection = False
78     try:
79         if not connection:
80             local_connection = True
81             connection = connect()
82         post = ''
83         if query:
84             post = '*'
85         filterstr = '(|%s)' % (
86             u' '.join([u'(%s=*%s%s)' % (field, query, post)
87                        for field in ['cn', 'rdn', 'uid', 'mail']]))
88         r = connection.search_s(
89             CONFIG.get('connection', 'basedn'),
90             ldap.SCOPE_SUBTREE,
91             filterstr.encode('utf-8'))
92     finally:
93         if local_connection and connection:
94             connection.unbind()
95     return r
96
97 def format_entry(entry):
98     cn,data = entry
99     if 'mail' in data:
100         for m in data['mail']:
101             yield email.utils.formataddr((data['cn'][-1], m))
102
103
104 if __name__ == '__main__':
105     import sys
106
107     query = unicode(' '.join(sys.argv[1:]), 'utf-8')
108     entries = search(query)
109     addresses = list(itertools.chain(
110             *[format_entry(e) for e in sorted(entries)]))
111     print '%d addresses found:' % len(addresses)
112     print '\n'.join(addresses)