4 Copyright (C) Andrew Bartlett 2007
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Component: ldb ranged results module
25 * Description: munge AD-style 'ranged results' requests into
26 * requests for all values in an attribute, then return the range to
29 * Author: Andrew Bartlett
33 #include "ldb_module.h"
36 struct ldb_module
*module
;
37 struct ldb_request
*req
;
40 static struct rr_context
*rr_init_context(struct ldb_module
*module
,
41 struct ldb_request
*req
)
43 struct rr_context
*ac
;
45 ac
= talloc_zero(req
, struct rr_context
);
47 ldb_set_errstring(ldb_module_get_ctx(module
), "Out of Memory");
57 static int rr_search_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
59 struct ldb_context
*ldb
;
60 struct rr_context
*ac
;
63 ac
= talloc_get_type(req
->context
, struct rr_context
);
64 ldb
= ldb_module_get_ctx(ac
->module
);
67 return ldb_module_done(ac
->req
, NULL
, NULL
,
68 LDB_ERR_OPERATIONS_ERROR
);
70 if (ares
->error
!= LDB_SUCCESS
) {
71 return ldb_module_done(ac
->req
, ares
->controls
,
72 ares
->response
, ares
->error
);
75 if (ares
->type
== LDB_REPLY_REFERRAL
) {
76 return ldb_module_send_referral(ac
->req
, ares
->referral
);
79 if (ares
->type
== LDB_REPLY_DONE
) {
80 return ldb_module_done(ac
->req
, ares
->controls
,
81 ares
->response
, ares
->error
);
86 /* Find those that are range requests from the attribute list */
87 for (i
= 0; ac
->req
->op
.search
.attrs
[i
]; i
++) {
90 unsigned int start
, end
, orig_num_values
;
91 struct ldb_message_element
*el
;
92 struct ldb_val
*orig_values
;
93 p
= strchr(ac
->req
->op
.search
.attrs
[i
], ';');
97 if (strncasecmp(p
, ";range=", strlen(";range=")) != 0) {
100 if (sscanf(p
, ";range=%u-%u", &start
, &end
) != 2) {
101 if (sscanf(p
, ";range=%u-*", &start
) == 1) {
102 end
= (unsigned int)-1;
107 new_attr
= talloc_strndup(ac
->req
,
108 ac
->req
->op
.search
.attrs
[i
],
109 (size_t)(p
- ac
->req
->op
.search
.attrs
[i
]));
113 return ldb_module_done(ac
->req
, NULL
, NULL
,
114 LDB_ERR_OPERATIONS_ERROR
);
116 el
= ldb_msg_find_element(ares
->message
, new_attr
);
117 talloc_free(new_attr
);
121 if (end
>= (el
->num_values
- 1)) {
122 /* Need to leave the requested attribute in
123 * there (so add an empty one to match) */
125 end
= el
->num_values
- 1;
127 end_str
= talloc_asprintf(el
, "%u", end
);
130 return ldb_module_done(ac
->req
, NULL
, NULL
,
131 LDB_ERR_OPERATIONS_ERROR
);
134 /* If start is greater then where we are find the end to be */
139 orig_values
= el
->values
;
140 orig_num_values
= el
->num_values
;
142 if ((start
+ end
< start
) || (start
+ end
< end
)) {
143 ldb_asprintf_errstring(ldb
,
144 "range request error: start or end would overflow!");
145 return ldb_module_done(ac
->req
, NULL
, NULL
,
146 LDB_ERR_UNWILLING_TO_PERFORM
);
151 el
->values
= talloc_array(el
, struct ldb_val
, (end
- start
) + 1);
154 return ldb_module_done(ac
->req
, NULL
, NULL
,
155 LDB_ERR_OPERATIONS_ERROR
);
157 for (j
=start
; j
<= end
; j
++) {
158 el
->values
[el
->num_values
] = orig_values
[j
];
162 el
->name
= talloc_asprintf(el
, "%s;range=%u-%s", el
->name
, start
, end_str
);
165 return ldb_module_done(ac
->req
, NULL
, NULL
,
166 LDB_ERR_OPERATIONS_ERROR
);
170 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
174 static int rr_search(struct ldb_module
*module
, struct ldb_request
*req
)
176 struct ldb_context
*ldb
;
178 unsigned int start
, end
;
179 const char **new_attrs
= NULL
;
180 bool found_rr
= false;
181 struct ldb_request
*down_req
;
182 struct rr_context
*ac
;
185 ldb
= ldb_module_get_ctx(module
);
187 /* Strip the range request from the attribute */
188 for (i
= 0; req
->op
.search
.attrs
&& req
->op
.search
.attrs
[i
]; i
++) {
190 new_attrs
= talloc_realloc(req
, new_attrs
, const char *, i
+2);
191 new_attrs
[i
] = req
->op
.search
.attrs
[i
];
192 new_attrs
[i
+1] = NULL
;
193 p
= strchr(new_attrs
[i
], ';');
197 if (strncasecmp(p
, ";range=", strlen(";range=")) != 0) {
200 end
= (unsigned int)-1;
201 if (sscanf(p
, ";range=%u-*", &start
) != 1) {
202 if (sscanf(p
, ";range=%u-%u", &start
, &end
) != 2) {
203 ldb_asprintf_errstring(ldb
,
204 "range request error: "
205 "range request malformed");
206 return LDB_ERR_UNWILLING_TO_PERFORM
;
210 ldb_asprintf_errstring(ldb
, "range request error: start must not be greater than end");
211 return LDB_ERR_UNWILLING_TO_PERFORM
;
215 new_attrs
[i
] = talloc_strndup(new_attrs
, new_attrs
[i
],
216 (size_t)(p
- new_attrs
[i
]));
220 return LDB_ERR_OPERATIONS_ERROR
;
225 ac
= rr_init_context(module
, req
);
227 return LDB_ERR_OPERATIONS_ERROR
;
230 ret
= ldb_build_search_req_ex(&down_req
, ldb
, ac
,
232 req
->op
.search
.scope
,
236 ac
, rr_search_callback
,
238 if (ret
!= LDB_SUCCESS
) {
241 return ldb_next_request(module
, down_req
);
244 /* No change, just run the original request as if we were never here */
245 talloc_free(new_attrs
);
246 return ldb_next_request(module
, req
);
249 const struct ldb_module_ops ldb_ranged_results_module_ops
= {
250 .name
= "ranged_results",