1 /* $OpenBSD: auth.c,v 1.12 2017/01/20 11:55:08 benno Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <netinet/in.h> 22 23 #include <errno.h> 24 #include <openssl/sha.h> 25 #include <pwd.h> 26 #include <resolv.h> /* for b64_pton */ 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "ldapd.h" 32 #include "log.h" 33 34 static int 35 aci_matches(struct aci *aci, struct conn *conn, struct namespace *ns, 36 char *dn, int rights, enum scope scope) 37 { 38 struct btval key; 39 40 if ((rights & aci->rights) != rights) 41 return 0; 42 43 if (dn == NULL) 44 return 0; 45 46 if (aci->target != NULL) { 47 key.size = strlen(dn); 48 key.data = dn; 49 50 if (scope == LDAP_SCOPE_BASE) { 51 switch (aci->scope) { 52 case LDAP_SCOPE_BASE: 53 if (strcmp(dn, aci->target) != 0) 54 return 0; 55 break; 56 case LDAP_SCOPE_ONELEVEL: 57 if (!is_child_of(&key, aci->target)) 58 return 0; 59 break; 60 case LDAP_SCOPE_SUBTREE: 61 if (!has_suffix(&key, aci->target)) 62 return 0; 63 break; 64 } 65 } else if (scope == LDAP_SCOPE_ONELEVEL) { 66 switch (aci->scope) { 67 case LDAP_SCOPE_BASE: 68 return 0; 69 case LDAP_SCOPE_ONELEVEL: 70 if (strcmp(dn, aci->target) != 0) 71 return 0; 72 break; 73 case LDAP_SCOPE_SUBTREE: 74 if (!has_suffix(&key, aci->target)) 75 return 0; 76 break; 77 } 78 } else if (scope == LDAP_SCOPE_SUBTREE) { 79 switch (aci->scope) { 80 case LDAP_SCOPE_BASE: 81 case LDAP_SCOPE_ONELEVEL: 82 return 0; 83 case LDAP_SCOPE_SUBTREE: 84 if (!has_suffix(&key, aci->target)) 85 return 0; 86 break; 87 } 88 } 89 } 90 91 if (aci->subject != NULL) { 92 if (conn->binddn == NULL) 93 return 0; 94 if (strcmp(aci->subject, "@") == 0) { 95 if (strcmp(dn, conn->binddn) != 0) 96 return 0; 97 } else if (strcmp(aci->subject, conn->binddn) != 0) 98 return 0; 99 } 100 101 return 1; 102 } 103 104 /* Returns true (1) if conn is authorized for op on dn in namespace. 105 */ 106 int 107 authorized(struct conn *conn, struct namespace *ns, int rights, char *dn, 108 int scope) 109 { 110 struct aci *aci; 111 int type = ACI_ALLOW; 112 113 /* Root DN is always allowed. */ 114 if (conn->binddn != NULL) { 115 if (conf->rootdn != NULL && 116 strcasecmp(conn->binddn, conf->rootdn) == 0) 117 return 1; 118 if (ns != NULL && ns->rootdn != NULL && 119 strcasecmp(conn->binddn, ns->rootdn) == 0) 120 return 1; 121 } 122 123 /* Default to deny for write access. */ 124 if ((rights & (ACI_WRITE | ACI_CREATE)) != 0) 125 type = ACI_DENY; 126 127 log_debug("requesting %02X access to %s by %s, in namespace %s", 128 rights, 129 dn ? dn : "any", 130 conn->binddn ? conn->binddn : "any", 131 ns ? ns->suffix : "global"); 132 133 SIMPLEQ_FOREACH(aci, &conf->acl, entry) { 134 if (aci_matches(aci, conn, ns, dn, rights, scope)) { 135 type = aci->type; 136 log_debug("%s by: %s %02X access to %s by %s", 137 type == ACI_ALLOW ? "allowed" : "denied", 138 aci->type == ACI_ALLOW ? "allow" : "deny", 139 aci->rights, 140 aci->target ? aci->target : "any", 141 aci->subject ? aci->subject : "any"); 142 } 143 } 144 145 if (ns != NULL) { 146 SIMPLEQ_FOREACH(aci, &ns->acl, entry) { 147 if (aci_matches(aci, conn, ns, dn, rights, scope)) { 148 type = aci->type; 149 log_debug("%s by: %s %02X access to %s by %s", 150 type == ACI_ALLOW ? "allowed" : "denied", 151 aci->type == ACI_ALLOW ? "allow" : "deny", 152 aci->rights, 153 aci->target ? aci->target : "any", 154 aci->subject ? aci->subject : "any"); 155 } 156 } 157 } 158 159 return type == ACI_ALLOW ? 1 : 0; 160 } 161 162 static int 163 send_auth_request(struct request *req, const char *username, 164 const char *password) 165 { 166 struct auth_req auth_req; 167 168 memset(&auth_req, 0, sizeof(auth_req)); 169 if (strlcpy(auth_req.name, username, 170 sizeof(auth_req.name)) >= sizeof(auth_req.name)) 171 goto fail; 172 if (strlcpy(auth_req.password, password, 173 sizeof(auth_req.password)) >= sizeof(auth_req.password)) 174 goto fail; 175 auth_req.fd = req->conn->fd; 176 auth_req.msgid = req->msgid; 177 178 if (imsgev_compose(iev_ldapd, IMSG_LDAPD_AUTH, 0, 0, -1, &auth_req, 179 sizeof(auth_req)) == -1) 180 goto fail; 181 182 req->conn->bind_req = req; 183 return 0; 184 185 fail: 186 memset(&auth_req, 0, sizeof(auth_req)); 187 return -1; 188 } 189 190 /* 191 * Check password. Returns 1 if password matches, 2 if password matching 192 * is in progress, 0 on mismatch and -1 on error. 193 */ 194 static int 195 check_password(struct request *req, const char *stored_passwd, 196 const char *passwd) 197 { 198 unsigned char tmp[128]; 199 unsigned char md[SHA_DIGEST_LENGTH]; 200 char *encpw; 201 unsigned char *salt; 202 SHA_CTX ctx; 203 int sz; 204 205 if (stored_passwd == NULL) 206 return -1; 207 208 if (strncmp(stored_passwd, "{SHA}", 5) == 0) { 209 sz = b64_pton(stored_passwd + 5, tmp, sizeof(tmp)); 210 if (sz != SHA_DIGEST_LENGTH) 211 return (-1); 212 SHA1_Init(&ctx); 213 SHA1_Update(&ctx, passwd, strlen(passwd)); 214 SHA1_Final(md, &ctx); 215 return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0); 216 } else if (strncmp(stored_passwd, "{SSHA}", 6) == 0) { 217 sz = b64_pton(stored_passwd + 6, tmp, sizeof(tmp)); 218 if (sz <= SHA_DIGEST_LENGTH) 219 return (-1); 220 salt = tmp + SHA_DIGEST_LENGTH; 221 SHA1_Init(&ctx); 222 SHA1_Update(&ctx, passwd, strlen(passwd)); 223 SHA1_Update(&ctx, salt, sz - SHA_DIGEST_LENGTH); 224 SHA1_Final(md, &ctx); 225 return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0); 226 } else if (strncmp(stored_passwd, "{CRYPT}", 7) == 0) { 227 encpw = crypt(passwd, stored_passwd + 7); 228 if (encpw == NULL) 229 return (-1); 230 return (strcmp(encpw, stored_passwd + 7) == 0 ? 1 : 0); 231 } else if (strncmp(stored_passwd, "{BSDAUTH}", 9) == 0) { 232 if (send_auth_request(req, stored_passwd + 9, passwd) == -1) 233 return (-1); 234 return 2; /* Operation in progress. */ 235 } else 236 return (strcmp(stored_passwd, passwd) == 0 ? 1 : 0); 237 } 238 239 static int 240 ldap_auth_sasl(struct request *req, char *binddn, struct ber_element *params) 241 { 242 char *method; 243 char *authzid, *authcid, *password; 244 char *creds; 245 size_t len; 246 247 if (ber_scanf_elements(params, "{sx", &method, &creds, &len) != 0) 248 return LDAP_PROTOCOL_ERROR; 249 250 if (strcmp(method, "PLAIN") != 0) 251 return LDAP_STRONG_AUTH_NOT_SUPPORTED; 252 253 if ((req->conn->s_flags & F_SECURE) == 0) { 254 log_info("refusing plain sasl bind on insecure connection"); 255 return LDAP_CONFIDENTIALITY_REQUIRED; 256 } 257 258 authzid = creds; 259 authcid = memchr(creds, '\0', len); 260 if (authcid == NULL || authcid + 2 >= creds + len) 261 return LDAP_PROTOCOL_ERROR; 262 authcid++; 263 password = memchr(authcid, '\0', len - (authcid - creds)); 264 if (password == NULL || password + 2 >= creds + len) 265 return LDAP_PROTOCOL_ERROR; 266 password++; 267 268 log_debug("sasl authorization id = [%s]", authzid); 269 log_debug("sasl authentication id = [%s]", authcid); 270 271 if (send_auth_request(req, authcid, password) != 0) 272 return LDAP_OPERATIONS_ERROR; 273 274 free(req->conn->binddn); 275 req->conn->binddn = NULL; 276 if ((req->conn->pending_binddn = strdup(authcid)) == NULL) 277 return LDAP_OTHER; 278 279 return LDAP_SUCCESS; 280 } 281 282 static int 283 ldap_auth_simple(struct request *req, char *binddn, struct ber_element *auth) 284 { 285 int pwret = 0; 286 char *password; 287 char *user_password; 288 struct namespace *ns; 289 struct ber_element *elm = NULL, *pw = NULL; 290 291 if (*binddn == '\0') { 292 free(req->conn->binddn); /* anonymous bind */ 293 req->conn->binddn = NULL; 294 log_debug("anonymous bind"); 295 return LDAP_SUCCESS; 296 } 297 298 if ((req->conn->s_flags & F_SECURE) == 0) { 299 log_info("refusing non-anonymous bind on insecure connection"); 300 return LDAP_CONFIDENTIALITY_REQUIRED; 301 } 302 303 if (ber_scanf_elements(auth, "s", &password) != 0) 304 return LDAP_PROTOCOL_ERROR; 305 306 if (*password == '\0') { 307 /* Unauthenticated Authentication Mechanism of Simple Bind */ 308 log_debug("refusing unauthenticated bind"); 309 return LDAP_UNWILLING_TO_PERFORM; 310 } 311 312 if (conf->rootdn != NULL && strcmp(conf->rootdn, binddn) == 0) { 313 pwret = check_password(req, conf->rootpw, password); 314 } else if ((ns = namespace_lookup_base(binddn, 1)) == NULL) { 315 return LDAP_INVALID_CREDENTIALS; 316 } else if (ns->rootdn != NULL && strcmp(ns->rootdn, binddn) == 0) { 317 pwret = check_password(req, ns->rootpw, password); 318 } else if (namespace_has_referrals(ns)) { 319 return LDAP_INVALID_CREDENTIALS; 320 } else { 321 if (!authorized(req->conn, ns, ACI_BIND, binddn, 322 LDAP_SCOPE_BASE)) 323 return LDAP_INSUFFICIENT_ACCESS; 324 325 elm = namespace_get(ns, binddn); 326 if (elm == NULL && errno == ESTALE) { 327 if (namespace_queue_request(ns, req) != 0) 328 return LDAP_BUSY; 329 return -1; /* Database is being reopened. */ 330 } 331 332 if (elm != NULL) 333 pw = ldap_get_attribute(elm, "userPassword"); 334 if (pw != NULL) { 335 for (elm = pw->be_next->be_sub; elm; 336 elm = elm->be_next) { 337 if (ber_get_string(elm, &user_password) != 0) 338 continue; 339 pwret = check_password(req, user_password, password); 340 if (pwret >= 1) 341 break; 342 } 343 } 344 } 345 346 free(req->conn->binddn); 347 req->conn->binddn = NULL; 348 349 if (pwret == 1) { 350 if ((req->conn->binddn = strdup(binddn)) == NULL) 351 return LDAP_OTHER; 352 log_debug("successfully authenticated as %s", 353 req->conn->binddn); 354 return LDAP_SUCCESS; 355 } else if (pwret == 2) { 356 if ((req->conn->pending_binddn = strdup(binddn)) == NULL) 357 return LDAP_OTHER; 358 return -LDAP_SASL_BIND_IN_PROGRESS; 359 } else if (pwret == 0) 360 return LDAP_INVALID_CREDENTIALS; 361 else 362 return LDAP_OPERATIONS_ERROR; 363 } 364 365 void 366 ldap_bind_continue(struct conn *conn, int ok) 367 { 368 int rc; 369 370 if (ok) { 371 rc = LDAP_SUCCESS; 372 conn->binddn = conn->pending_binddn; 373 log_debug("successfully authenticated as %s", conn->binddn); 374 } else { 375 rc = LDAP_INVALID_CREDENTIALS; 376 free(conn->pending_binddn); 377 } 378 conn->pending_binddn = NULL; 379 380 ldap_respond(conn->bind_req, rc); 381 conn->bind_req = NULL; 382 } 383 384 int 385 ldap_bind(struct request *req) 386 { 387 int rc = LDAP_OTHER; 388 long long ver; 389 char *binddn; 390 struct ber_element *auth; 391 392 ++stats.req_bind; 393 394 if (ber_scanf_elements(req->op, "{ise", &ver, &binddn, &auth) != 0) { 395 rc = LDAP_PROTOCOL_ERROR; 396 goto done; 397 } 398 399 if (req->conn->bind_req) { 400 log_debug("aborting bind in progress with msgid %lld", 401 req->conn->bind_req->msgid); 402 request_free(req->conn->bind_req); 403 req->conn->bind_req = NULL; 404 } 405 406 normalize_dn(binddn); 407 log_debug("bind dn = %s", binddn); 408 409 switch (auth->be_type) { 410 case LDAP_AUTH_SIMPLE: 411 if ((rc = ldap_auth_simple(req, binddn, auth)) < 0) 412 return rc; 413 break; 414 case LDAP_AUTH_SASL: 415 if ((rc = ldap_auth_sasl(req, binddn, auth)) == LDAP_SUCCESS) 416 return LDAP_SUCCESS; 417 break; 418 default: 419 rc = LDAP_STRONG_AUTH_NOT_SUPPORTED; 420 break; 421 } 422 423 done: 424 return ldap_respond(req, rc); 425 } 426 427