4 * A module which implements the LDAP connector for Citadel.
16 #include <sys/types.h>
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
23 # include <sys/time.h>
34 #include "sysdep_decls.h"
35 #include "citserver.h"
38 #include "serv_extensions.h"
43 #include "serv_ldap.h"
51 LDAP *dirserver = NULL;
54 * LDAP connector cleanup function
56 void serv_ldap_cleanup(void)
58 if (!dirserver) return;
60 lprintf(7, "Unbinding from directory server\n");
61 ldap_unbind(dirserver);
65 #endif /* HAVE_LDAP */
68 void CtdlConnectToLdap(void) {
72 lprintf(7, "Connecting to LDAP server %s:%d...\n",
73 config.c_ldap_host, config.c_ldap_port);
75 dirserver = ldap_init(config.c_ldap_host, config.c_ldap_port);
76 if (dirserver == NULL) {
77 lprintf(3, "Could not connect to %s:%d : %s\n",
84 ldap_set_option(dirserver, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
86 lprintf(7, "Binding to %s\n", config.c_ldap_bind_dn);
88 i = ldap_simple_bind_s(dirserver,
89 config.c_ldap_bind_dn,
92 if (i != LDAP_SUCCESS) {
93 lprintf(3, "Cannot bind: %s (%d)\n", ldap_err2string(i), i);
94 dirserver = NULL; /* FIXME disconnect from ldap */
101 * Write (add, or change if already exists) a directory entry to the
102 * LDAP server, based on the information supplied in a vCard.
104 void ctdl_vcard_to_ldap(struct CtdlMessage *msg) {
105 struct vCard *v = NULL;
108 LDAPMod **attrs = NULL;
114 if (dirserver == NULL) return;
115 if (msg == NULL) return;
116 if (msg->cm_fields['M'] == NULL) return;
117 if (msg->cm_fields['A'] == NULL) return;
118 if (msg->cm_fields['N'] == NULL) return;
120 /* Initialize variables */
121 strcpy(givenname, "_");
124 sprintf(this_dn, "cn=%s,ou=%s,%s",
127 config.c_ldap_base_dn
130 /* The first LDAP attribute will be an 'objectclass' list. Citadel
131 * doesn't do anything with this. It's just there for compatibility
135 attrs = mallok( (sizeof(LDAPMod *) * num_attrs) );
136 attrs[0] = mallok(sizeof(LDAPMod));
137 memset(attrs[0], 0, sizeof(LDAPMod));
138 attrs[0]->mod_op = LDAP_MOD_ADD;
139 attrs[0]->mod_type = "objectclass";
140 attrs[0]->mod_values = mallok(5 * sizeof(char *));
141 attrs[0]->mod_values[0] = strdoop("inetOrgPerson");
142 attrs[0]->mod_values[1] = strdoop("organizationalPerson");
143 attrs[0]->mod_values[2] = strdoop("person");
144 attrs[0]->mod_values[3] = strdoop("Top");
145 attrs[0]->mod_values[4] = NULL;
147 /* Add a "cn" (Common Name) attribute based on the user's screen name */
148 attrs = reallok(attrs, (sizeof(LDAPMod *) * ++num_attrs) );
149 attrs[num_attrs-1] = mallok(sizeof(LDAPMod));
150 memset(attrs[num_attrs-1], 0, sizeof(LDAPMod));
151 attrs[num_attrs-1]->mod_op = LDAP_MOD_ADD;
152 attrs[num_attrs-1]->mod_type = "cn";
153 attrs[num_attrs-1]->mod_values = mallok(2 * sizeof(char *));
154 attrs[num_attrs-1]->mod_values[0] = strdoop(msg->cm_fields['A']);
155 attrs[num_attrs-1]->mod_values[1] = NULL;
157 /* Convert the vCard fields to LDAP properties */
158 v = vcard_load(msg->cm_fields['M']);
159 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
161 if (!strcasecmp(v->prop[i].name, "n")) {
162 extract_token(sn, v->prop[i].value, 0, ';');
163 extract_token(givenname, v->prop[i].value, 1, ';');
167 vcard_free(v); /* Don't need this anymore. */
169 /* "sn" (surname) based on info in vCard */
170 attrs = reallok(attrs, (sizeof(LDAPMod *) * ++num_attrs) );
171 attrs[num_attrs-1] = mallok(sizeof(LDAPMod));
172 memset(attrs[num_attrs-1], 0, sizeof(LDAPMod));
173 attrs[num_attrs-1]->mod_op = LDAP_MOD_ADD;
174 attrs[num_attrs-1]->mod_type = "sn";
175 attrs[num_attrs-1]->mod_values = mallok(2 * sizeof(char *));
176 attrs[num_attrs-1]->mod_values[0] = strdoop(sn);
177 attrs[num_attrs-1]->mod_values[1] = NULL;
179 /* "givenname" (first name) based on info in vCard */
180 attrs = reallok(attrs, (sizeof(LDAPMod *) * ++num_attrs) );
181 attrs[num_attrs-1] = mallok(sizeof(LDAPMod));
182 memset(attrs[num_attrs-1], 0, sizeof(LDAPMod));
183 attrs[num_attrs-1]->mod_op = LDAP_MOD_ADD;
184 attrs[num_attrs-1]->mod_type = "givenname";
185 attrs[num_attrs-1]->mod_values = mallok(2 * sizeof(char *));
186 attrs[num_attrs-1]->mod_values[0] = strdoop(givenname);
187 attrs[num_attrs-1]->mod_values[1] = NULL;
189 /* The last attribute must be a NULL one. */
190 attrs = realloc(attrs, (sizeof(LDAPMod *) * ++num_attrs) );
191 attrs[num_attrs - 1] = NULL;
193 lprintf(9, "this_dn: <%s>\n", this_dn);
195 lprintf(9, "Calling ldap_add_s()\n");
196 begin_critical_section(S_LDAP);
197 i = ldap_add_s(dirserver, this_dn, attrs);
198 end_critical_section(S_LDAP);
200 /* If the entry already exists, repopulate it instead */
201 if (i == LDAP_ALREADY_EXISTS) {
202 for (j=0; j<(num_attrs-1); ++j) {
203 attrs[j]->mod_op = LDAP_MOD_REPLACE;
205 lprintf(9, "Calling ldap_modify_s()\n");
206 begin_critical_section(S_LDAP);
207 i = ldap_modify_s(dirserver, this_dn, attrs);
208 end_critical_section(S_LDAP);
211 if (i != LDAP_SUCCESS) {
212 lprintf(3, "ldap_add_s() failed: %s (%d)\n",
213 ldap_err2string(i), i);
216 lprintf(9, "Freeing attributes\n");
217 /* Free the attributes */
218 for (i=0; i<num_attrs; ++i) {
219 if (attrs[i] != NULL) {
221 /* First, free the value strings */
222 if (attrs[i]->mod_values != NULL) {
223 for (j=0; attrs[i]->mod_values[j] != NULL; ++j) {
224 phree(attrs[i]->mod_values[j]);
228 /* Free the value strings pointer list */
229 if (attrs[i]->mod_values != NULL) {
230 phree(attrs[i]->mod_values);
233 /* Now free the LDAPMod struct itself. */
238 lprintf(9, "LDAP operation complete.\n");
245 * Initialize the LDAP connector module ... or don't, if we don't have LDAP.
247 char *serv_ldap_init(void)
250 CtdlRegisterCleanupHook(serv_ldap_cleanup);
252 if (strlen(config.c_ldap_host) > 0) {
256 #endif /* HAVE_LDAP */