* by ano: use more uniq name in the ldap module; the old one clashed in solaris.
[citadel.git] / citadel / ldap.c
1 /*
2  * $Id$
3  *
4  * These functions implement the portions of AUTHMODE_LDAP and AUTHMODE_LDAP_AD which
5  * actually speak to the LDAP server.
6  *
7  * Copyright (c) 2009 by Art Cancro and the citadel.org development team.
8  * This program is released under the terms of the GNU General Public License v3
9  */
10
11
12 int ctdl_require_ldap_version = 3;
13
14
15 #include "sysdep.h"
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <pwd.h>
23 #include <ctype.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #ifdef HAVE_SYS_STAT_H
27 #include <sys/stat.h>
28 #endif
29
30 #if TIME_WITH_SYS_TIME
31 # include <sys/time.h>
32 # include <time.h>
33 #else
34 # if HAVE_SYS_TIME_H
35 #  include <sys/time.h>
36 # else
37 #  include <time.h>
38 # endif
39 #endif
40
41 #include <string.h>
42 #include <limits.h>
43 #include <libcitadel.h>
44 #include "auth.h"
45 #include "citadel.h"
46 #include "server.h"
47 #include "database.h"
48 #include "user_ops.h"
49 #include "sysdep_decls.h"
50 #include "support.h"
51 #include "room_ops.h"
52 #include "file_ops.h"
53 #include "control.h"
54 #include "msgbase.h"
55 #include "config.h"
56 #include "citserver.h"
57 #include "citadel_dirs.h"
58 #include "genstamp.h"
59 #include "threads.h"
60 #include "citadel_ldap.h"
61
62 #ifdef HAVE_LDAP
63
64 #define LDAP_DEPRECATED 1       /* Needed to suppress misleading warnings */
65
66 #include <ldap.h>
67
68 int CtdlTryUserLDAP(char *username,
69                 char *found_dn, int found_dn_size,
70                 char *fullname, int fullname_size,
71                 uid_t *uid)
72 {
73         LDAP *ldserver = NULL;
74         int i;
75         LDAPMessage *search_result = NULL;
76         LDAPMessage *entry = NULL;
77         char searchstring[1024];
78         struct timeval tv;
79         char **values;
80         char *user_dn = NULL;
81
82         if (fullname) safestrncpy(fullname, username, fullname_size);
83
84         ldserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
85         if (ldserver == NULL) {
86                 CtdlLogPrintf(CTDL_ALERT, "LDAP: Could not connect to %s:%d : %s\n",
87                         config.c_ldap_host, config.c_ldap_port,
88                         strerror(errno));
89                 return(errno);
90         }
91
92         ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ctdl_require_ldap_version);
93
94         striplt(config.c_ldap_bind_dn);
95         striplt(config.c_ldap_bind_pw);
96         i = ldap_simple_bind_s(ldserver,
97                 (!IsEmptyStr(config.c_ldap_bind_dn) ? config.c_ldap_bind_dn : NULL),
98                 (!IsEmptyStr(config.c_ldap_bind_pw) ? config.c_ldap_bind_pw : NULL)
99         );
100         if (i != LDAP_SUCCESS) {
101                 CtdlLogPrintf(CTDL_ALERT, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
102                 return(i);
103         }
104
105         tv.tv_sec = 10;
106         tv.tv_usec = 0;
107
108         if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
109                 sprintf(searchstring, "(sAMAccountName=%s)", username);
110         }
111         else {
112                 sprintf(searchstring, "(&(objectclass=posixAccount)(uid=%s))", username);
113         }
114
115         i = ldap_search_st(ldserver,
116                 config.c_ldap_base_dn,
117                 LDAP_SCOPE_SUBTREE,
118                 searchstring,
119                 NULL,   // return all attributes
120                 0,      // attributes + values
121                 &tv,    // timeout
122                 &search_result
123         );
124         if (i != LDAP_SUCCESS) {
125                 CtdlLogPrintf(CTDL_DEBUG,
126                         "Couldn't find what I was looking for: %s (%d)\n", ldap_err2string(i), i);
127                 ldap_unbind(ldserver);
128                 return(i);
129         }
130
131         if (search_result == NULL) {
132                 CtdlLogPrintf(CTDL_DEBUG, "No results were returned\n");
133                 ldap_unbind(ldserver);
134                 return(2);
135         }
136
137         /* At this point we've got at least one result from our query.  If there are multiple
138          * results, we still only look at the first one.
139          */
140         entry = ldap_first_entry(ldserver, search_result);
141         if (entry) {
142
143                 user_dn = ldap_get_dn(ldserver, entry);
144                 if (user_dn) {
145                         CtdlLogPrintf(CTDL_DEBUG, "dn = %s\n", user_dn);
146                 }
147
148                 if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
149                         values = ldap_get_values(ldserver, search_result, "displayName");
150                         if (values) {
151                                 if (values[0]) {
152                                         if (fullname) safestrncpy(fullname, values[0], fullname_size);
153                                         CtdlLogPrintf(CTDL_DEBUG, "displayName = %s\n", values[0]);
154                                 }
155                                 ldap_value_free(values);
156                         }
157                 }
158                 else {
159                         values = ldap_get_values(ldserver, search_result, "cn");
160                         if (values) {
161                                 if (values[0]) {
162                                         if (fullname) safestrncpy(fullname, values[0], fullname_size);
163                                         CtdlLogPrintf(CTDL_DEBUG, "cn = %s\n", values[0]);
164                                 }
165                                 ldap_value_free(values);
166                         }
167                 }
168
169                 if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
170                         values = ldap_get_values(ldserver, search_result, "objectGUID");
171                         if (values) {
172                                 if (values[0]) {
173                                         if (uid != NULL) {
174                                                 *uid = abs(HashLittle(values[0], strlen(values[0])));
175                                                 CtdlLogPrintf(CTDL_DEBUG, "uid hashed from objectGUID = %d\n", *uid);
176                                         }
177                                 }
178                                 ldap_value_free(values);
179                         }
180                 }
181                 else {
182                         values = ldap_get_values(ldserver, search_result, "uidNumber");
183                         if (values) {
184                                 if (values[0]) {
185                                         CtdlLogPrintf(CTDL_DEBUG, "uidNumber = %s\n", values[0]);
186                                         if (uid != NULL) {
187                                                 *uid = atoi(values[0]);
188                                         }
189                                 }
190                                 ldap_value_free(values);
191                         }
192                 }
193
194         }
195
196         /* free the results */
197         ldap_msgfree(search_result);
198
199         /* unbind so we can go back in as the authenticating user */
200         ldap_unbind(ldserver);
201
202         if (!user_dn) {
203                 CtdlLogPrintf(CTDL_DEBUG, "No such user was found.\n");
204                 return(4);
205         }
206
207         if (found_dn) safestrncpy(found_dn, user_dn, found_dn_size);
208         ldap_memfree(user_dn);
209         return(0);
210 }
211
212
213 int CtdlTryPasswordLDAP(char *user_dn, char *password)
214 {
215         LDAP *ldserver = NULL;
216         int i = (-1);
217
218         ldserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
219         if (ldserver) {
220                 ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ctdl_require_ldap_version);
221                 i = ldap_simple_bind_s(ldserver, user_dn, password);
222                 if (i == LDAP_SUCCESS) {
223                         CtdlLogPrintf(CTDL_DEBUG, "LDAP: bind succeeded\n");
224                 }
225                 else {
226                         CtdlLogPrintf(CTDL_DEBUG, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
227                 }
228                 ldap_unbind(ldserver);
229         }
230
231         if (i == LDAP_SUCCESS) {
232                 return(0);
233         }
234
235         return(1);
236 }
237
238
239 /*
240  * Learn LDAP attributes and stuff them into the vCard.
241  * Returns nonzero if we changed anything.
242  */
243 int Ctdl_LDAP_to_vCard(char *ldap_dn, struct vCard *v)
244 {
245         if (!ldap_dn) return(0);
246         if (!v) return(0);
247
248         /*
249          * FIXME LDAPSTUB this is a stub function
250          *
251          * ldap_dn will contain the DN of the user, and v will contain a pointer to
252          * the vCard that needs to be (re-)populated.  Put the requisite LDAP code here.
253          *
254         vcard_set_prop(v, "email;internet", xxx, 0);
255         return(1);      * return nonzero to tell the caller that we made changes that need to be saved *
256          *
257          */
258
259         return(0);      /* return zero to tell the caller that we didn't make any changes */
260 }
261
262 #endif /* HAVE_LDAP */