Bump version
[public/pyceo-broken.git] / src / ldap.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <pwd.h>
4 #include <grp.h>
5 #include <sasl/sasl.h>
6 #include <krb5.h>
7
8 #define LDAP_DEPRECATED 1
9 #include <ldap.h>
10
11 #include "ldap.h"
12 #include "krb5.h"
13 #include "config.h"
14 #include "util.h"
15
16 extern char *prog;
17
18 LDAP *ld;
19
20 static void ldap_fatal(char *msg) {
21     int errnum = 0;
22     char *errstr = NULL;
23     char *detail = NULL;
24
25     if (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &errnum) != LDAP_SUCCESS)
26         warn("ldap_get_option(LDAP_OPT_ERROR_NUMBER) failed");
27     if (ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &detail) != LDAP_SUCCESS)
28         warn("ldap_get_option(LDAP_OPT_ERROR_STRING) failed");
29
30     errstr = ldap_err2string(errnum);
31
32     if (detail)
33         fatal("%s: %s (%d): %s", msg, errstr, errnum, detail);
34     else if (errnum)
35         fatal("%s: %s (%d)", msg, errstr, errnum);
36     else
37         fatal("%s", msg);
38 }
39
40 static void ldap_err(char *msg) {
41     int errnum = 0;
42     char *errstr = NULL;
43     char *detail = NULL;
44
45     if (ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &errnum) != LDAP_SUCCESS)
46         warn("ldap_get_option(LDAP_OPT_ERROR_NUMBER) failed");
47     if (ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &detail) != LDAP_SUCCESS)
48         warn("ldap_get_option(LDAP_OPT_ERROR_STRING) failed");
49
50     errstr = ldap_err2string(errnum);
51
52     if (detail)
53         error("%s: %s (%d): %s", msg, errstr, errnum, detail);
54     else if (errnum)
55         error("%s: %s (%d)", msg, errstr, errnum);
56     else
57         error("%s", msg);
58 }
59
60 int ceo_add_group(char *cn, char *basedn, int no) {
61     if (!cn || !basedn)
62         fatal("addgroup: Invalid argument");
63
64     LDAPMod *mods[8];
65     int i = -1;
66     int ret = 0;
67
68     mods[++i] = xmalloc(sizeof(LDAPMod));
69     mods[i]->mod_op = LDAP_MOD_ADD;
70     mods[i]->mod_type = "objectClass";
71     char *objectClasses[] = { "top", "group", "posixGroup", NULL };
72     mods[i]->mod_values = objectClasses;
73
74     mods[++i] = xmalloc(sizeof(LDAPMod));
75     mods[i]->mod_op = LDAP_MOD_ADD;
76     mods[i]->mod_type = "cn";
77     char *uids[] = { cn, NULL };
78     mods[i]->mod_values = uids;
79
80     mods[++i] = xmalloc(sizeof(LDAPMod));
81     mods[i]->mod_op = LDAP_MOD_ADD;
82     mods[i]->mod_type = "gidNumber";
83     char idno[16];
84     snprintf(idno, sizeof(idno), "%d", no);
85     char *gidNumbers[] = { idno, NULL };
86     mods[i]->mod_values = gidNumbers;
87
88     mods[++i] = NULL;
89
90     char dn[1024];
91     snprintf(dn, sizeof(dn), "cn=%s,%s", cn, basedn);
92
93     if (ldap_add_s(ld, dn, mods) != LDAP_SUCCESS) {
94         ldap_err("addgroup");
95         ret = -1;
96     }
97
98     for (i = 0; mods[i]; i++)
99         free(mods[i]);
100
101     return ret;
102 }
103
104 int ceo_add_group_sudo(char *group, char *basedn) {
105     if (!group || !basedn)
106         fatal("addgroup: Invalid argument");
107
108     LDAPMod *mods[8];
109     int i = -1;
110     int ret = 0;
111
112     char cn[17];
113     snprintf(cn, sizeof(cn), "%%%s", group);
114
115     mods[++i] = xmalloc(sizeof(LDAPMod));
116     mods[i]->mod_op = LDAP_MOD_ADD;
117     mods[i]->mod_type = "objectClass";
118     char *objectClasses[] = { "top", "sudoRole", NULL };
119     mods[i]->mod_values = objectClasses;
120
121     mods[++i] = xmalloc(sizeof(LDAPMod));
122     mods[i]->mod_op = LDAP_MOD_ADD;
123     mods[i]->mod_type = "cn";
124     char *uids[] = { cn, NULL };
125     mods[i]->mod_values = uids;
126
127     mods[++i] = xmalloc(sizeof(LDAPMod));
128     mods[i]->mod_op = LDAP_MOD_ADD;
129     mods[i]->mod_type = "sudoUser";
130     char *sudouser[] = { cn, NULL };
131     mods[i]->mod_values = sudouser;
132
133     mods[++i] = xmalloc(sizeof(LDAPMod));
134     mods[i]->mod_op = LDAP_MOD_ADD;
135     mods[i]->mod_type = "sudoHost";
136     char *sudohost[] = { "ALL", NULL };
137     mods[i]->mod_values = sudohost;
138
139     mods[++i] = xmalloc(sizeof(LDAPMod));
140     mods[i]->mod_op = LDAP_MOD_ADD;
141     mods[i]->mod_type = "sudoCommand";
142     char *sudocommand[] = { "ALL", NULL };
143     mods[i]->mod_values = sudocommand;
144
145     mods[++i] = xmalloc(sizeof(LDAPMod));
146     mods[i]->mod_op = LDAP_MOD_ADD;
147     mods[i]->mod_type = "sudoOption";
148     char *sudooption[] = { "!authenticate", NULL };
149     mods[i]->mod_values = sudooption;
150
151     mods[++i] = xmalloc(sizeof(LDAPMod));
152     mods[i]->mod_op = LDAP_MOD_ADD;
153     mods[i]->mod_type = "sudoRunAs";
154     char *sudorunas[] = { group, NULL };
155     mods[i]->mod_values = sudorunas;
156
157     char dn[1024];
158     snprintf(dn, sizeof(dn), "cn=%%%s,%s", group, basedn);
159
160     mods[++i] = NULL;
161
162     if (ldap_add_s(ld, dn, mods) != LDAP_SUCCESS) {
163         ldap_err("addgroup");
164         ret = -1;
165     }
166
167     for (i = 0; mods[i]; i++)
168         free(mods[i]);
169
170     return ret;
171 }
172
173 int ceo_add_user(char *uid, char *basedn, char *objclass, char *cn, char *home, char *principal, char *shell, int no, ...) {
174     va_list args;
175
176     if (!uid || !basedn || !cn || !home || !shell)
177         fatal("adduser: Invalid argument");
178
179     LDAPMod *mods[16];
180     char *vals[16][2];
181     int i = -1;
182     int ret = 0;
183     int classes = 4;
184
185     mods[++i] = xmalloc(sizeof(LDAPMod));
186     mods[i]->mod_op = LDAP_MOD_ADD;
187     mods[i]->mod_type = "objectClass";
188     char *objectClasses[] = { "top", "account", "posixAccount", "shadowAccount", NULL, NULL, NULL, NULL };
189     if (objclass != NULL)
190         objectClasses[classes++] = objclass;
191     if (principal) {
192         objectClasses[classes++] = "krbPrincipalAux";
193         objectClasses[classes++] = "krbTicketPolicyAux";
194
195     }
196     mods[i]->mod_values = objectClasses;
197
198     mods[++i] = xmalloc(sizeof(LDAPMod));
199     mods[i]->mod_op = LDAP_MOD_ADD;
200     mods[i]->mod_type = "uid";
201     char *uids[] = { uid, NULL };
202     mods[i]->mod_values = uids;
203
204     mods[++i] = xmalloc(sizeof(LDAPMod));
205     mods[i]->mod_op = LDAP_MOD_ADD;
206     mods[i]->mod_type = "cn";
207     char *cns[] = { cn, NULL };
208     mods[i]->mod_values = cns;
209
210     mods[++i] = xmalloc(sizeof(LDAPMod));
211     mods[i]->mod_op = LDAP_MOD_ADD;
212     mods[i]->mod_type = "loginShell";
213     char *shells[] = { shell, NULL };
214     mods[i]->mod_values = shells;
215
216     mods[++i] = xmalloc(sizeof(LDAPMod));
217     mods[i]->mod_op = LDAP_MOD_ADD;
218     mods[i]->mod_type = "uidNumber";
219     char idno[16];
220     snprintf(idno, sizeof(idno), "%d", no);
221     char *uidNumbers[] = { idno, NULL };
222     mods[i]->mod_values = uidNumbers;
223
224     mods[++i] = xmalloc(sizeof(LDAPMod));
225     mods[i]->mod_op = LDAP_MOD_ADD;
226     mods[i]->mod_type = "gidNumber";
227     mods[i]->mod_values = uidNumbers;
228
229     mods[++i] = xmalloc(sizeof(LDAPMod));
230     mods[i]->mod_op = LDAP_MOD_ADD;
231     mods[i]->mod_type = "homeDirectory";
232     char *homeDirectory[] = { home, NULL };
233     mods[i]->mod_values = homeDirectory;
234
235     if (principal) {
236         mods[++i] = xmalloc(sizeof(LDAPMod));
237         mods[i]->mod_op = LDAP_MOD_ADD;
238         mods[i]->mod_type = "krbPrincipalName";
239         vals[i][0] = principal;
240         vals[i][1] = NULL;
241         mods[i]->mod_values = vals[i];
242     }
243
244     va_start(args, no);
245     char *attr;
246     while ((attr = va_arg(args, char *))) {
247         char *val = va_arg(args, char *);
248
249         if (!val || !*val)
250             continue;
251
252         if (i == sizeof(mods) / sizeof(*mods) - 2) {
253             error("too many attributes");
254             return -1;
255         }
256
257         mods[++i] = xmalloc(sizeof(LDAPMod));
258         mods[i]->mod_op = LDAP_MOD_ADD;
259         mods[i]->mod_type = attr;
260         vals[i][0] = val;
261         vals[i][1] = NULL;
262         mods[i]->mod_values = vals[i];
263     }
264
265     mods[++i] = NULL;
266
267     char dn[1024];
268     snprintf(dn, sizeof(dn), "uid=%s,%s", uid, basedn);
269
270     if (ldap_add_s(ld, dn, mods) != LDAP_SUCCESS) {
271         ldap_err("adduser");
272         ret = -1;
273     }
274
275     for (i = 0; mods[i]; i++)
276         free(mods[i]);
277
278     return ret;
279 }
280
281 int ceo_new_uid(int min, int max) {
282     char filter[64];
283     char *attrs[] = { LDAP_NO_ATTRS, NULL };
284     LDAPMessage *res;
285     int i;
286
287     for (i = min; i <= max; i++) {
288         // id taken due to passwd
289         if (getpwuid(i) != NULL)
290             continue;
291
292         // id taken due to group
293         if (getgrgid(i) != NULL)
294             continue;
295
296         snprintf(filter, sizeof(filter), "(|(uidNumber=%d)(gidNumber=%d))", i, i);
297         if (ldap_search_s(ld, ldap_users_base, LDAP_SCOPE_SUBTREE, filter, attrs, 1, &res) != LDAP_SUCCESS) {
298             ldap_err("firstuid");
299             return -1;
300         }
301
302         int count = ldap_count_entries(ld, res);
303         ldap_msgfree(res);
304
305         // id taken due to LDAP
306         if (count)
307             continue;
308
309         return i;
310     }
311
312     return -1;
313 }
314
315 int ceo_user_exists(char *uid) {
316     char *attrs[] = { LDAP_NO_ATTRS, NULL };
317     LDAPMessage *msg = NULL;
318     char filter[128];
319     int count;
320
321     if (!uid)
322         fatal("null uid");
323
324     snprintf(filter, sizeof(filter), "uid=%s", uid);
325
326     if (ldap_search_s(ld, ldap_users_base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg) != LDAP_SUCCESS) {
327         ldap_err("user_exists");
328         return -1;
329     }
330
331     count = ldap_count_entries(ld, msg);
332     ldap_msgfree(msg);
333
334     return count > 0;
335 }
336
337 int ceo_group_exists(char *cn) {
338     char *attrs[] = { LDAP_NO_ATTRS, NULL };
339     LDAPMessage *msg = NULL;
340     char filter[128];
341     int count;
342
343     if (!cn)
344         fatal("null cd");
345
346     snprintf(filter, sizeof(filter), "cn=%s", cn);
347
348     if (ldap_search_s(ld, ldap_groups_base, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &msg) != LDAP_SUCCESS) {
349         ldap_err("group_exists");
350         return -1;
351     }
352
353     count = ldap_count_entries(ld, msg);
354     ldap_msgfree(msg);
355
356     return count > 0;
357 }
358
359 static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in) {
360     sasl_interact_t *interact = in;
361
362     while (interact->id != SASL_CB_LIST_END) {
363         switch (interact->id) {
364
365             // GSSAPI doesn't require any callbacks
366
367             default:
368                 interact->result = "";
369                 interact->len = 0;
370         }
371
372         interact++;
373     }
374
375     return LDAP_SUCCESS;
376 }
377
378 void ceo_ldap_init() {
379     int proto = LDAP_DEFAULT_PROTOCOL;
380
381     if (!ldap_admin_principal)
382         fatal("not configured");
383
384     if (ldap_initialize(&ld, ldap_server_url) != LDAP_SUCCESS)
385         ldap_fatal("ldap_initialize");
386
387     if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &proto) != LDAP_OPT_SUCCESS)
388         ldap_fatal("ldap_set_option");
389
390     if (ldap_sasl_interactive_bind_s(ld, NULL, ldap_sasl_mech, NULL, NULL,
391                 LDAP_SASL_QUIET, &ldap_sasl_interact, NULL) != LDAP_SUCCESS)
392         ldap_fatal("Bind failed");
393 }
394
395 void ceo_ldap_cleanup() {
396     ldap_unbind(ld);
397 }