1 1.3 christos /* $NetBSD: search.c,v 1.4 2025/09/05 21:16:27 christos Exp $ */ 2 1.2 christos 3 1.1 lukem /* search.c - DNS SRV backend search function */ 4 1.2 christos /* $OpenLDAP$ */ 5 1.1 lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 1.1 lukem * 7 1.4 christos * Copyright 2000-2024 The OpenLDAP Foundation. 8 1.1 lukem * Portions Copyright 2000-2003 Kurt D. Zeilenga. 9 1.1 lukem * All rights reserved. 10 1.1 lukem * 11 1.1 lukem * Redistribution and use in source and binary forms, with or without 12 1.1 lukem * modification, are permitted only as authorized by the OpenLDAP 13 1.1 lukem * Public License. 14 1.1 lukem * 15 1.1 lukem * A copy of this license is available in the file LICENSE in the 16 1.1 lukem * top-level directory of the distribution or, alternatively, at 17 1.1 lukem * <http://www.OpenLDAP.org/license.html>. 18 1.1 lukem */ 19 1.1 lukem /* ACKNOWLEDGEMENTS: 20 1.1 lukem * This work was originally developed by Kurt D. Zeilenga for inclusion 21 1.1 lukem * in OpenLDAP Software. 22 1.1 lukem */ 23 1.1 lukem 24 1.2 christos #include <sys/cdefs.h> 25 1.3 christos __RCSID("$NetBSD: search.c,v 1.4 2025/09/05 21:16:27 christos Exp $"); 26 1.2 christos 27 1.1 lukem #include "portable.h" 28 1.1 lukem 29 1.1 lukem #include <stdio.h> 30 1.1 lukem 31 1.1 lukem #include <ac/socket.h> 32 1.1 lukem #include <ac/string.h> 33 1.1 lukem #include <ac/time.h> 34 1.1 lukem 35 1.1 lukem #include "slap.h" 36 1.1 lukem #include "proto-dnssrv.h" 37 1.1 lukem 38 1.1 lukem int 39 1.1 lukem dnssrv_back_search( 40 1.1 lukem Operation *op, 41 1.1 lukem SlapReply *rs ) 42 1.1 lukem { 43 1.1 lukem int i; 44 1.1 lukem int rc; 45 1.1 lukem char *domain = NULL; 46 1.1 lukem char *hostlist = NULL; 47 1.1 lukem char **hosts = NULL; 48 1.1 lukem char *refdn; 49 1.1 lukem struct berval nrefdn = BER_BVNULL; 50 1.1 lukem BerVarray urls = NULL; 51 1.1 lukem int manageDSAit; 52 1.1 lukem 53 1.1 lukem rs->sr_ref = NULL; 54 1.1 lukem 55 1.1 lukem if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { 56 1.1 lukem /* FIXME: need some means to determine whether the database 57 1.1 lukem * is a glue instance; if we got here with empty DN, then 58 1.1 lukem * we passed this same test in dnssrv_back_referrals() */ 59 1.1 lukem if ( !SLAP_GLUE_INSTANCE( op->o_bd ) ) { 60 1.1 lukem rs->sr_err = LDAP_UNWILLING_TO_PERFORM; 61 1.1 lukem rs->sr_text = "DNS SRV operation upon null (empty) DN disallowed"; 62 1.1 lukem 63 1.1 lukem } else { 64 1.1 lukem rs->sr_err = LDAP_SUCCESS; 65 1.1 lukem } 66 1.1 lukem goto done; 67 1.1 lukem } 68 1.1 lukem 69 1.1 lukem manageDSAit = get_manageDSAit( op ); 70 1.1 lukem /* 71 1.1 lukem * FIXME: we may return a referral if manageDSAit is not set 72 1.1 lukem */ 73 1.1 lukem if ( !manageDSAit ) { 74 1.1 lukem send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, 75 1.1 lukem "manageDSAit must be set" ); 76 1.1 lukem goto done; 77 1.1 lukem } 78 1.1 lukem 79 1.1 lukem if( ldap_dn2domain( op->o_req_dn.bv_val, &domain ) || domain == NULL ) { 80 1.1 lukem rs->sr_err = LDAP_REFERRAL; 81 1.1 lukem rs->sr_ref = default_referral; 82 1.1 lukem send_ldap_result( op, rs ); 83 1.1 lukem rs->sr_ref = NULL; 84 1.1 lukem goto done; 85 1.1 lukem } 86 1.1 lukem 87 1.1 lukem Debug( LDAP_DEBUG_TRACE, "DNSSRV: dn=\"%s\" -> domain=\"%s\"\n", 88 1.3 christos op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", domain ); 89 1.1 lukem 90 1.1 lukem if( ( rc = ldap_domain2hostlist( domain, &hostlist ) ) ) { 91 1.1 lukem Debug( LDAP_DEBUG_TRACE, "DNSSRV: domain2hostlist returned %d\n", 92 1.3 christos rc ); 93 1.1 lukem send_ldap_error( op, rs, LDAP_NO_SUCH_OBJECT, 94 1.1 lukem "no DNS SRV RR available for DN" ); 95 1.1 lukem goto done; 96 1.1 lukem } 97 1.1 lukem 98 1.1 lukem hosts = ldap_str2charray( hostlist, " " ); 99 1.1 lukem 100 1.1 lukem if( hosts == NULL ) { 101 1.3 christos Debug( LDAP_DEBUG_TRACE, "DNSSRV: str2charray error\n" ); 102 1.1 lukem send_ldap_error( op, rs, LDAP_OTHER, 103 1.1 lukem "problem processing DNS SRV records for DN" ); 104 1.1 lukem goto done; 105 1.1 lukem } 106 1.1 lukem 107 1.1 lukem for( i=0; hosts[i] != NULL; i++) { 108 1.1 lukem struct berval url; 109 1.1 lukem 110 1.1 lukem url.bv_len = STRLENOF( "ldap://" ) + strlen(hosts[i]); 111 1.1 lukem url.bv_val = ch_malloc( url.bv_len + 1 ); 112 1.1 lukem 113 1.1 lukem strcpy( url.bv_val, "ldap://" ); 114 1.1 lukem strcpy( &url.bv_val[STRLENOF( "ldap://" )], hosts[i] ); 115 1.1 lukem 116 1.1 lukem if( ber_bvarray_add( &urls, &url ) < 0 ) { 117 1.1 lukem free( url.bv_val ); 118 1.1 lukem send_ldap_error( op, rs, LDAP_OTHER, 119 1.1 lukem "problem processing DNS SRV records for DN" ); 120 1.1 lukem goto done; 121 1.1 lukem } 122 1.1 lukem } 123 1.1 lukem 124 1.3 christos Debug( LDAP_DEBUG_STATS, 125 1.1 lukem "%s DNSSRV p=%d dn=\"%s\" url=\"%s\"\n", 126 1.1 lukem op->o_log_prefix, op->o_protocol, 127 1.3 christos op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", urls[0].bv_val ); 128 1.1 lukem 129 1.1 lukem Debug( LDAP_DEBUG_TRACE, 130 1.1 lukem "DNSSRV: ManageDSAit scope=%d dn=\"%s\" -> url=\"%s\"\n", 131 1.1 lukem op->oq_search.rs_scope, 132 1.1 lukem op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", 133 1.1 lukem urls[0].bv_val ); 134 1.1 lukem 135 1.1 lukem rc = ldap_domain2dn(domain, &refdn); 136 1.1 lukem 137 1.1 lukem if( rc != LDAP_SUCCESS ) { 138 1.1 lukem send_ldap_error( op, rs, LDAP_OTHER, 139 1.1 lukem "DNS SRV problem processing manageDSAit control" ); 140 1.1 lukem goto done; 141 1.1 lukem 142 1.1 lukem } else { 143 1.1 lukem struct berval bv; 144 1.1 lukem bv.bv_val = refdn; 145 1.1 lukem bv.bv_len = strlen( refdn ); 146 1.1 lukem 147 1.1 lukem rc = dnNormalize( 0, NULL, NULL, &bv, &nrefdn, op->o_tmpmemctx ); 148 1.1 lukem if( rc != LDAP_SUCCESS ) { 149 1.1 lukem send_ldap_error( op, rs, LDAP_OTHER, 150 1.1 lukem "DNS SRV problem processing manageDSAit control" ); 151 1.1 lukem goto done; 152 1.1 lukem } 153 1.1 lukem } 154 1.1 lukem 155 1.1 lukem if( !dn_match( &nrefdn, &op->o_req_ndn ) ) { 156 1.1 lukem /* requested dn is subordinate */ 157 1.1 lukem 158 1.1 lukem Debug( LDAP_DEBUG_TRACE, 159 1.1 lukem "DNSSRV: dn=\"%s\" subordinate to refdn=\"%s\"\n", 160 1.1 lukem op->o_req_dn.bv_len ? op->o_req_dn.bv_val : "", 161 1.3 christos refdn == NULL ? "" : refdn ); 162 1.1 lukem 163 1.1 lukem rs->sr_matched = refdn; 164 1.1 lukem rs->sr_err = LDAP_NO_SUCH_OBJECT; 165 1.1 lukem send_ldap_result( op, rs ); 166 1.1 lukem rs->sr_matched = NULL; 167 1.1 lukem 168 1.1 lukem } else if ( op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) { 169 1.1 lukem send_ldap_error( op, rs, LDAP_SUCCESS, NULL ); 170 1.1 lukem 171 1.1 lukem } else { 172 1.1 lukem Entry e = { 0 }; 173 1.1 lukem AttributeDescription *ad_objectClass 174 1.1 lukem = slap_schema.si_ad_objectClass; 175 1.1 lukem AttributeDescription *ad_ref = slap_schema.si_ad_ref; 176 1.2 christos e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val ); 177 1.1 lukem e.e_name.bv_len = op->o_req_dn.bv_len; 178 1.2 christos e.e_nname.bv_val = ch_strdup( op->o_req_ndn.bv_val ); 179 1.1 lukem e.e_nname.bv_len = op->o_req_ndn.bv_len; 180 1.1 lukem 181 1.1 lukem e.e_attrs = NULL; 182 1.1 lukem e.e_private = NULL; 183 1.1 lukem 184 1.1 lukem attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_referral->soc_cname, NULL ); 185 1.1 lukem attr_merge_one( &e, ad_objectClass, &slap_schema.si_oc_extensibleObject->soc_cname, NULL ); 186 1.1 lukem 187 1.1 lukem if ( ad_dc ) { 188 1.1 lukem char *p; 189 1.1 lukem struct berval bv; 190 1.1 lukem 191 1.1 lukem bv.bv_val = domain; 192 1.1 lukem 193 1.1 lukem p = strchr( bv.bv_val, '.' ); 194 1.1 lukem 195 1.1 lukem if ( p == bv.bv_val ) { 196 1.1 lukem bv.bv_len = 1; 197 1.1 lukem 198 1.1 lukem } else if ( p != NULL ) { 199 1.1 lukem bv.bv_len = p - bv.bv_val; 200 1.1 lukem 201 1.1 lukem } else { 202 1.1 lukem bv.bv_len = strlen( bv.bv_val ); 203 1.1 lukem } 204 1.1 lukem 205 1.1 lukem attr_merge_normalize_one( &e, ad_dc, &bv, NULL ); 206 1.1 lukem } 207 1.1 lukem 208 1.1 lukem if ( ad_associatedDomain ) { 209 1.1 lukem struct berval bv; 210 1.1 lukem 211 1.1 lukem ber_str2bv( domain, 0, 0, &bv ); 212 1.1 lukem attr_merge_normalize_one( &e, ad_associatedDomain, &bv, NULL ); 213 1.1 lukem } 214 1.1 lukem 215 1.1 lukem attr_merge_normalize_one( &e, ad_ref, urls, NULL ); 216 1.1 lukem 217 1.1 lukem rc = test_filter( op, &e, op->oq_search.rs_filter ); 218 1.1 lukem 219 1.1 lukem if( rc == LDAP_COMPARE_TRUE ) { 220 1.1 lukem rs->sr_entry = &e; 221 1.1 lukem rs->sr_attrs = op->oq_search.rs_attrs; 222 1.1 lukem rs->sr_flags = REP_ENTRY_MODIFIABLE; 223 1.1 lukem send_search_entry( op, rs ); 224 1.1 lukem rs->sr_entry = NULL; 225 1.1 lukem rs->sr_attrs = NULL; 226 1.2 christos rs->sr_flags = 0; 227 1.1 lukem } 228 1.1 lukem 229 1.1 lukem entry_clean( &e ); 230 1.1 lukem 231 1.1 lukem rs->sr_err = LDAP_SUCCESS; 232 1.1 lukem send_ldap_result( op, rs ); 233 1.1 lukem } 234 1.1 lukem 235 1.2 christos free( refdn ); 236 1.1 lukem if ( nrefdn.bv_val ) free( nrefdn.bv_val ); 237 1.1 lukem 238 1.1 lukem done: 239 1.1 lukem if( domain != NULL ) ch_free( domain ); 240 1.1 lukem if( hostlist != NULL ) ch_free( hostlist ); 241 1.1 lukem if( hosts != NULL ) ldap_charray_free( hosts ); 242 1.1 lukem if( urls != NULL ) ber_bvarray_free( urls ); 243 1.1 lukem return 0; 244 1.1 lukem } 245