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 };