* Added a separate authentication mode AUTHMODE_LDAP_AD for Active Directory's nonsta...
[citadel.git] / citadel / ldap.c
1 /*
2  * 
3  */
4
5
6 int ldap_version = 3;
7
8
9 #include "sysdep.h"
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <pwd.h>
17 #include <ctype.h>
18 #include <sys/types.h>
19 #include <sys/wait.h>
20 #ifdef HAVE_SYS_STAT_H
21 #include <sys/stat.h>
22 #endif
23
24 #if TIME_WITH_SYS_TIME
25 # include <sys/time.h>
26 # include <time.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 #  include <sys/time.h>
30 # else
31 #  include <time.h>
32 # endif
33 #endif
34
35 #include <string.h>
36 #include <limits.h>
37 #include <libcitadel.h>
38 #include "auth.h"
39 #include "citadel.h"
40 #include "server.h"
41 #include "database.h"
42 #include "user_ops.h"
43 #include "sysdep_decls.h"
44 #include "support.h"
45 #include "room_ops.h"
46 #include "file_ops.h"
47 #include "control.h"
48 #include "msgbase.h"
49 #include "config.h"
50 #include "citserver.h"
51 #include "citadel_dirs.h"
52 #include "genstamp.h"
53 #include "threads.h"
54 #include "citadel_ldap.h"
55
56 #ifdef HAVE_LDAP
57
58 #define LDAP_DEPRECATED 1       /* Needed to suppress misleading warnings */
59
60 #include <ldap.h>
61
62 int CtdlTryUserLDAP(char *username,
63                 char *found_dn, int found_dn_size,
64                 char *fullname, int fullname_size,
65                 uid_t *uid)
66 {
67         LDAP *ldserver = NULL;
68         int i;
69         LDAPMessage *search_result = NULL;
70         LDAPMessage *entry = NULL;
71         char searchstring[1024];
72         struct timeval tv;
73         char **values;
74         char *user_dn = NULL;
75
76         if (fullname) safestrncpy(fullname, username, fullname_size);
77
78         ldserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
79         if (ldserver == NULL) {
80                 CtdlLogPrintf(CTDL_ALERT, "LDAP: Could not connect to %s:%d : %s\n",
81                         config.c_ldap_host, config.c_ldap_port,
82                         strerror(errno));
83                 return(errno);
84         }
85
86         ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
87
88         striplt(config.c_ldap_bind_dn);
89         striplt(config.c_ldap_bind_pw);
90         i = ldap_simple_bind_s(ldserver,
91                 (!IsEmptyStr(config.c_ldap_bind_dn) ? config.c_ldap_bind_dn : NULL),
92                 (!IsEmptyStr(config.c_ldap_bind_pw) ? config.c_ldap_bind_pw : NULL)
93         );
94         if (i != LDAP_SUCCESS) {
95                 CtdlLogPrintf(CTDL_ALERT, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
96                 return(i);
97         }
98
99         tv.tv_sec = 10;
100         tv.tv_usec = 0;
101
102         if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
103                 sprintf(searchstring, "(sAMAccountName=%s)", username);
104         }
105         else {
106                 sprintf(searchstring, "(&(objectclass=posixAccount)(uid=%s))", username);
107         }
108
109         i = ldap_search_st(ldserver,
110                 config.c_ldap_base_dn,
111                 LDAP_SCOPE_SUBTREE,
112                 searchstring,
113                 NULL,   // return all attributes
114                 0,      // attributes + values
115                 &tv,    // timeout
116                 &search_result
117         );
118         if (i != LDAP_SUCCESS) {
119                 CtdlLogPrintf(CTDL_DEBUG,
120                         "Couldn't find what I was looking for: %s (%d)\n", ldap_err2string(i), i);
121                 ldap_unbind(ldserver);
122                 return(i);
123         }
124
125         if (search_result == NULL) {
126                 CtdlLogPrintf(CTDL_DEBUG, "No results were returned\n");
127                 ldap_unbind(ldserver);
128                 return(2);
129         }
130
131         /* At this point we've got at least one result from our query.  If there are multiple
132          * results, we still only look at the first one.
133          */
134         entry = ldap_first_entry(ldserver, search_result);
135         if (entry) {
136
137                 user_dn = ldap_get_dn(ldserver, entry);
138                 if (user_dn) {
139                         CtdlLogPrintf(CTDL_DEBUG, "dn = %s\n", user_dn);
140                 }
141
142                 if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
143                         values = ldap_get_values(ldserver, search_result, "displayName");
144                         if (values) {
145                                 if (values[0]) {
146                                         if (fullname) safestrncpy(fullname, values[0], fullname_size);
147                                         CtdlLogPrintf(CTDL_DEBUG, "displayName = %s\n", values[0]);
148                                 }
149                                 ldap_value_free(values);
150                         }
151                 }
152                 else {
153                         values = ldap_get_values(ldserver, search_result, "cn");
154                         if (values) {
155                                 if (values[0]) {
156                                         if (fullname) safestrncpy(fullname, values[0], fullname_size);
157                                         CtdlLogPrintf(CTDL_DEBUG, "cn = %s\n", values[0]);
158                                 }
159                                 ldap_value_free(values);
160                         }
161                 }
162
163                 if (config.c_auth_mode == AUTHMODE_LDAP_AD) {
164                         values = ldap_get_values(ldserver, search_result, "objectGUID");
165                         if (values) {
166                                 if (values[0]) {
167                                         if (uid != NULL) {
168                                                 *uid = abs(HashLittle(values[0], strlen(values[0])));
169                                                 CtdlLogPrintf(CTDL_DEBUG, "uid hashed from objectGUID = %d\n", *uid);
170                                         }
171                                 }
172                                 ldap_value_free(values);
173                         }
174                 }
175                 else {
176                         values = ldap_get_values(ldserver, search_result, "uidNumber");
177                         if (values) {
178                                 if (values[0]) {
179                                         CtdlLogPrintf(CTDL_DEBUG, "uidNumber = %s\n", values[0]);
180                                         if (uid != NULL) {
181                                                 *uid = atoi(values[0]);
182                                         }
183                                 }
184                                 ldap_value_free(values);
185                         }
186                 }
187
188         }
189
190         /* free the results */
191         ldap_msgfree(search_result);
192
193         /* unbind so we can go back in as the authenticating user */
194         ldap_unbind(ldserver);
195
196         if (!user_dn) {
197                 CtdlLogPrintf(CTDL_DEBUG, "No such user was found.\n");
198                 return(4);
199         }
200
201         if (found_dn) safestrncpy(found_dn, user_dn, found_dn_size);
202         ldap_memfree(user_dn);
203         return(0);
204 }
205
206
207 int CtdlTryPasswordLDAP(char *user_dn, char *password)
208 {
209         LDAP *ldserver = NULL;
210         int i = (-1);
211
212         ldserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
213         if (ldserver) {
214                 ldap_set_option(ldserver, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
215                 i = ldap_simple_bind_s(ldserver, user_dn, password);
216                 if (i == LDAP_SUCCESS) {
217                         CtdlLogPrintf(CTDL_DEBUG, "LDAP: bind succeeded\n");
218                 }
219                 else {
220                         CtdlLogPrintf(CTDL_DEBUG, "LDAP: Cannot bind: %s (%d)\n", ldap_err2string(i), i);
221                 }
222                 ldap_unbind(ldserver);
223         }
224
225         if (i == LDAP_SUCCESS) {
226                 return(0);
227         }
228
229         return(1);
230 }
231
232
233
234
235 #endif /* HAVE_LDAP */