waffle

user and group backend daemon
git clone git://git.2f30.org/waffle.git
Log | Files | Refs | LICENSE

ldap.c (6427B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <ctype.h>
      3 #include <errno.h>
      4 #include <limits.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <ldap.h>
      9 #include "waffle.h"
     10 
     11 struct ldap_config {
     12 	char *host;
     13 	int port;
     14 	int version;
     15 	char *uri;
     16 	char *rootbinddn;
     17 	char *binddn;
     18 	char *bindpw;
     19 	char *base;
     20 	int debug;
     21 };
     22 
     23 static LDAP *ld;
     24 static struct ldap_config ldap_conf;
     25 
     26 static void
     27 free_config(void)
     28 {
     29 	free(ldap_conf.host);
     30 	free(ldap_conf.uri);
     31 	free(ldap_conf.rootbinddn);
     32 	free(ldap_conf.binddn);
     33 	free(ldap_conf.bindpw);
     34 	free(ldap_conf.base);
     35 	memset(&ldap_conf, 0, sizeof(ldap_conf));
     36 }
     37 
     38 static int
     39 parse_config(void)
     40 {
     41 	FILE *fp;
     42 	char buf[BUFSIZ], *p;
     43 	char *key, *val;
     44 	char *end;
     45 
     46 	fp = fopen(LDAP_CFG_PATH, "r");
     47 	while (fp && fgets(buf, sizeof(buf), fp)) {
     48 		p = buf;
     49 		if (*p == '#' || *p == '\n' || !*p)
     50 			continue;
     51 
     52 		/* strip leading whitespace before key */
     53 		while(isspace(*p))
     54 			p++;
     55 		key = p;
     56 
     57 		/* null-terminate key */
     58 		while (*p && !isspace(*p)) p++;
     59 		if (*p)
     60 			*p++ = '\0';
     61 
     62 		/* strip leading whitespace before val */
     63 		while (isspace(*p))
     64 			p++;
     65 		val = p;
     66 
     67 		/* strip trailing whitespace after val */
     68 		while (*p)
     69 			p++;
     70 		while (--p > val && isspace(*p))
     71 			*p = '\0';
     72 
     73 		if (!strcmp(key, "host")) {
     74 			ldap_conf.host = strdup(val);
     75 			if (!ldap_conf.host)
     76 				goto out;
     77 		} else if (!strcmp(key, "port")) {
     78 			errno = 0;
     79 			ldap_conf.port = strtol(val, &end, 10);
     80 			if (*end || errno)
     81 				goto out;
     82 		} else if (!strcmp(key, "ldap_version")) {
     83 			errno = 0;
     84 			ldap_conf.version = strtol(val, &end, 10);
     85 			if (*end || errno)
     86 				goto out;
     87 		} else if (!strcmp(key, "uri")) {
     88 			ldap_conf.uri = strdup(val);
     89 			if (!ldap_conf.uri)
     90 				goto out;
     91 		} else if (!strcmp(key, "rootbinddn")) {
     92 			ldap_conf.rootbinddn = strdup(val);
     93 			if (!ldap_conf.rootbinddn)
     94 				goto out;
     95 		} else if (!strcmp(key, "binddn")) {
     96 			ldap_conf.binddn = strdup(val);
     97 			if (!ldap_conf.binddn)
     98 				goto out;
     99 		} else if (!strcmp(key, "bindpw")) {
    100 			ldap_conf.bindpw = strdup(val);
    101 			if (!ldap_conf.bindpw)
    102 				goto out;
    103 		} else if (!strcmp(key, "base")) {
    104 			ldap_conf.base = strdup(val);
    105 			if (!ldap_conf.base)
    106 				goto out;
    107 		} else if (!strcmp(key, "debug")) {
    108 			errno = 0;
    109 			ldap_conf.debug = strtol(val, &end, 10);
    110 			if (*end || errno)
    111 				goto out;
    112 		} else {
    113 			logwarn("unknown keyword in ldap.conf: %s\n",
    114 			        key);
    115 		}
    116 	}
    117 	if (fp)
    118 		fclose(fp);
    119 	if (!ldap_conf.host)
    120 		ldap_conf.host = strdup("localhost");
    121 	if (!ldap_conf.port)
    122 		ldap_conf.port = 389;
    123 	if (!ldap_conf.version)
    124 		ldap_conf.version = 3;
    125 	if (!ldap_conf.base)
    126 		goto out;
    127 	return 0;
    128 out:
    129 	free_config();
    130 	return -1;
    131 }
    132 
    133 static int
    134 init(void)
    135 {
    136 	int version = LDAP_VERSION3;
    137 	int r;
    138 
    139 	if (parse_config() < 0)
    140 		return -1;
    141 	if (ldap_conf.version != 3) {
    142 		logwarn("unsupported LDAP version: %d\n", ldap_conf.version);
    143 		goto out1;
    144 	}
    145 
    146 	if (ldap_conf.uri) {
    147 		r = ldap_initialize(&ld, ldap_conf.uri);
    148 		if (r != LDAP_SUCCESS) {
    149 			logwarn("ldap_initialize: %s\n", strerror(errno));
    150 			goto out1;
    151 		}
    152 	} else if (ldap_conf.host) {
    153 		ld = ldap_init(ldap_conf.host, ldap_conf.port);
    154 		if (!ld) {
    155 			logwarn("ldap_init: %s\n", strerror(errno));
    156 			goto out1;
    157 		}
    158 	}
    159 
    160 	r = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
    161 	if (r != LDAP_SUCCESS) {
    162 		logwarn("ldap_set_option: %s\n", ldap_err2string(r));
    163 		goto out2;
    164 	}
    165 
    166 	r = ldap_bind_s(ld, ldap_conf.rootbinddn, ldap_conf.bindpw,
    167 	                LDAP_AUTH_SIMPLE);
    168 	if (r != LDAP_SUCCESS) {
    169 		logwarn("ldap_simple_bind_s: %s\n", ldap_err2string(r));
    170 		goto out2;
    171 	}
    172 
    173 	return 0;
    174 out2:
    175 	ldap_destroy(ld);
    176 	ld = NULL;
    177 out1:
    178 	free_config();
    179 	return -1;
    180 }
    181 
    182 static void
    183 term(void)
    184 {
    185 	if (ld) {
    186 		ldap_unbind(ld);
    187 		ldap_destroy(ld);
    188 		ld = NULL;
    189 	}
    190 	free_config();
    191 }
    192 
    193 static int
    194 pw_query(const char *name, const char *filter, struct passwd *pw)
    195 {
    196 	LDAPMessage *result = NULL, *e = NULL;
    197 	BerElement *ber = NULL;
    198 	struct berval **bv;
    199 	char *a;
    200 	char *end;
    201 	int r;
    202 
    203 	r = ldap_search_s(ld, ldap_conf.base, LDAP_SCOPE_SUBTREE,
    204 	                  filter, NULL, 0, &result);
    205 	if (r != LDAP_SUCCESS) {
    206 		logwarn("ldap_search_s: %s\n", ldap_err2string(r));
    207 		return -1;
    208 	}
    209 
    210 	e = ldap_first_entry(ld, result);
    211 	if (!e) {
    212 		ldap_msgfree(result);
    213 		return -1;
    214 	}
    215 
    216 	for (a = ldap_first_attribute(ld, e, &ber); a;
    217 	     a = ldap_next_attribute(ld, e, ber)) {
    218 		if (!(bv = ldap_get_values_len(ld, e, a)))
    219 			goto out;
    220 		if (!strcmp(a, "uid")) {
    221 			pw->pw_name = strdup(bv[0]->bv_val);
    222 			if (!pw->pw_name) {
    223 				ldap_value_free_len(bv);
    224 				goto out;
    225 			}
    226 		} else if (!strcmp(a, "userPassword")) {
    227 			pw->pw_passwd = strdup(bv[0]->bv_val);
    228 			if (!pw->pw_passwd) {
    229 				ldap_value_free_len(bv);
    230 				goto out;
    231 			}
    232 		} else if (!strcmp(a, "uidNumber")) {
    233 			errno = 0;
    234 			pw->pw_uid = strtol(bv[0]->bv_val, &end, 10);
    235 			if (*end || errno) {
    236 				ldap_value_free_len(bv);
    237 				goto out;
    238 			}
    239 		} else if (!strcmp(a, "gidNumber")) {
    240 			errno = 0;
    241 			pw->pw_gid = strtol(bv[0]->bv_val, &end, 10);
    242 			if (*end || errno) {
    243 				ldap_value_free_len(bv);
    244 				goto out;
    245 			}
    246 		} else if (!strcmp(a, "gecos")) {
    247 			pw->pw_gecos = strdup(bv[0]->bv_val);
    248 			if (!pw->pw_gecos) {
    249 				ldap_value_free_len(bv);
    250 				goto out;
    251 			}
    252 		} else if (!strcmp(a, "homeDirectory")) {
    253 			pw->pw_dir = strdup(bv[0]->bv_val);
    254 			if (!pw->pw_dir) {
    255 				ldap_value_free_len(bv);
    256 				goto out;
    257 			}
    258 		} else if (!strcmp(a, "loginShell")) {
    259 			pw->pw_shell = strdup(bv[0]->bv_val);
    260 			if (!pw->pw_shell) {
    261 				ldap_value_free_len(bv);
    262 				goto out;
    263 			}
    264 		}
    265 		ldap_value_free_len(bv);
    266 	}
    267 	ber_free(ber, 0);
    268 	ldap_msgfree(result);
    269 	return 0;
    270 out:
    271 	ber_free(ber, 0);
    272 	ldap_msgfree(result);
    273 	return -1;
    274 }
    275 
    276 static int
    277 pwbyname(const char *name, struct passwd *pw)
    278 {
    279 	char filter[strlen("uid=") + LOGIN_NAME_MAX];
    280 	snprintf(filter, sizeof(filter), "uid=%s", name);
    281 	return pw_query(name, filter, pw);
    282 }
    283 
    284 static int
    285 pwbyuid(uid_t uid, struct passwd *pw)
    286 {
    287 	char key[11]; /* max digits in 2^32 + null-terminator */
    288 	char filter[strlen("uidNumber=") + 11];
    289 
    290 	snprintf(filter, sizeof(filter), "uidNumber=%d", uid);
    291 	snprintf(key, sizeof(key), "%d", uid);
    292 	return pw_query(key, filter, pw);
    293 }
    294 
    295 static int
    296 grbyname(const char *name, struct group *gr)
    297 {
    298 	return -1;
    299 }
    300 
    301 static int
    302 grbygid(gid_t gid, struct group *gr)
    303 {
    304 	return -1;
    305 }
    306 
    307 struct backend_ops ldap_ops = {
    308 	.init = init,
    309 	.term = term,
    310 	.pwbyname = pwbyname,
    311 	.pwbyuid = pwbyuid,
    312 	.grbyname = grbyname,
    313 	.grbygid = grbygid,
    314 };