]> git.sur5r.net Git - openldap/blob - servers/slapd/back-passwd/search.c
Build without HAVE_TLS
[openldap] / servers / slapd / back-passwd / search.c
1 /* search.c - /etc/passwd backend search function */
2 /* $OpenLDAP$ */
3
4 #include "portable.h"
5
6 #include <stdio.h>
7
8 #include <ac/ctype.h>
9 #include <ac/socket.h>
10 #include <ac/string.h>
11 #include <ac/time.h>
12
13 #include <pwd.h>
14
15 #include "slap.h"
16 #include "back-passwd.h"
17 #include <ldap_pvt.h>
18
19 static void pw_start( Backend *be );
20
21 static Entry *pw2entry(
22         Backend *be,
23         struct passwd *pw,
24         const char **text);
25
26 int
27 passwd_back_search(
28     Operation   *op,
29     SlapReply   *rs )
30 {
31         struct passwd   *pw;
32         Entry           *e;
33         char            *s;
34         time_t          stoptime;
35
36         LDAPRDN rdn = NULL;
37         struct berval parent = { 0, NULL };
38
39         AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
40
41         op->oq_search.rs_tlimit = (op->oq_search.rs_tlimit > op->o_bd->be_timelimit || op->oq_search.rs_tlimit < 1) ? op->o_bd->be_timelimit
42             : op->oq_search.rs_tlimit;
43         stoptime = op->o_time + op->oq_search.rs_tlimit;
44         op->oq_search.rs_slimit = (op->oq_search.rs_slimit > op->o_bd->be_sizelimit || op->oq_search.rs_slimit < 1) ? op->o_bd->be_sizelimit
45             : op->oq_search.rs_slimit;
46
47         /* Handle a query for the base of this backend */
48         if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
49                 struct berval   vals[2];
50
51                 vals[1].bv_val = NULL;
52
53                 rs->sr_matched = op->o_req_dn.bv_val;
54
55                 if( op->oq_search.rs_scope != LDAP_SCOPE_ONELEVEL ) {
56                         AttributeDescription *desc = NULL;
57
58                         /* Create an entry corresponding to the base DN */
59                         e = (Entry *) ch_calloc(1, sizeof(Entry));
60                         e->e_name.bv_val = ch_strdup( op->o_req_dn.bv_val );
61                         e->e_name.bv_len = op->o_req_dn.bv_len;
62                         e->e_nname.bv_val =  ch_strdup( op->o_req_ndn.bv_val );
63                         e->e_nname.bv_len = op->o_req_ndn.bv_len;
64                         e->e_attrs = NULL;
65                         e->e_private = NULL;
66
67                         /* Use the first attribute of the DN
68                         * as an attribute within the entry itself.
69                         */
70                         if( ldap_bv2rdn( &op->o_req_dn, &rdn, (char **)&rs->sr_text, 
71                                 LDAP_DN_FORMAT_LDAP ) )
72                         {
73                                 rs->sr_err = LDAP_INVALID_DN_SYNTAX;
74                                 goto done;
75                         }
76
77                         if( slap_bv2ad( &rdn[0]->la_attr, &desc, &rs->sr_text )) {
78                                 rs->sr_err = LDAP_NO_SUCH_OBJECT;
79                                 ldap_rdnfree(rdn);
80                                 goto done;
81                         }
82
83                         vals[0] = rdn[0]->la_value;
84                         attr_mergeit( e, desc, vals );
85
86                         ldap_rdnfree(rdn);
87                         rdn = NULL;
88
89                         /* Every entry needs an objectclass. We don't really
90                          * know if our hardcoded choice here agrees with the
91                          * DN that was configured for this backend, but it's
92                          * better than nothing.
93                          *
94                          * should be a configuratable item
95                          */
96                         vals[0].bv_val = "organizationalUnit";
97                         vals[0].bv_len = sizeof("organizationalUnit")-1;
98                         attr_mergeit( e, ad_objectClass, vals );
99         
100                         if ( test_filter( op, e, op->oq_search.rs_filter ) == LDAP_COMPARE_TRUE ) {
101                                 rs->sr_entry = e;
102                                 rs->sr_attrs = op->oq_search.rs_attrs;
103                                 send_search_entry( op, rs );
104                         }
105                 }
106
107                 if ( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
108                         /* check all our "children" */
109
110                         ldap_pvt_thread_mutex_lock( &passwd_mutex );
111                         pw_start( op->o_bd );
112                         for ( pw = getpwent(); pw != NULL; pw = getpwent() ) {
113                                 /* check for abandon */
114                                 if ( op->o_abandon ) {
115                                         endpwent();
116                                         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
117                                         return( -1 );
118                                 }
119
120                                 /* check time limit */
121                                 if ( slap_get_time() > stoptime ) {
122                                         send_ldap_error( op, rs, LDAP_TIMELIMIT_EXCEEDED, NULL );
123                                         endpwent();
124                                         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
125                                         return( 0 );
126                                 }
127
128                                 if ( !(e = pw2entry( op->o_bd, pw, &rs->sr_text )) ) {
129                                         rs->sr_err = LDAP_OTHER;
130                                         endpwent();
131                                         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
132                                         goto done;
133                                 }
134
135                                 if ( test_filter( op, e, op->oq_search.rs_filter ) == LDAP_COMPARE_TRUE ) {
136                                         /* check size limit */
137                                         if ( --op->oq_search.rs_slimit == -1 ) {
138                                                 send_ldap_error( op, rs, LDAP_SIZELIMIT_EXCEEDED, NULL );
139                                                 endpwent();
140                                                 ldap_pvt_thread_mutex_unlock( &passwd_mutex );
141                                                 return( 0 );
142                                         }
143
144                                         rs->sr_entry = e;
145                                         rs->sr_attrs = op->oq_search.rs_attrs;
146                                         send_search_entry( op, rs );
147                                 }
148
149                                 entry_free( e );
150                         }
151                         endpwent();
152                         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
153                 }
154
155         } else {
156                 if (! be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
157                         dnParent( &op->o_req_ndn, &parent );
158                 }
159
160                 /* This backend is only one layer deep. Don't answer requests for
161                  * anything deeper than that.
162                  */
163                 if( !be_issuffix( op->o_bd, &parent ) ) {
164                         int i;
165                         for( i=0; op->o_bd->be_nsuffix[i].bv_val != NULL; i++ ) {
166                                 if( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_nsuffix[i] ) ) {
167                                         rs->sr_matched = op->o_bd->be_suffix[i].bv_val;
168                                         break;
169                                 }
170                         }
171                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
172                         goto done;
173                 }
174
175                 if( op->oq_search.rs_scope == LDAP_SCOPE_ONELEVEL ) {
176                         goto done;
177                 }
178
179                 if ( ldap_bv2rdn( &op->o_req_dn, &rdn, (char **)&rs->sr_text,
180                         LDAP_DN_FORMAT_LDAP ))
181                 { 
182                         rs->sr_err = LDAP_OTHER;
183                         goto done;
184                 }
185
186                 ldap_pvt_thread_mutex_lock( &passwd_mutex );
187                 pw_start( op->o_bd );
188                 if ( (pw = getpwnam( rdn[0]->la_value.bv_val )) == NULL ) {
189                         rs->sr_matched = parent.bv_val;
190                         rs->sr_err = LDAP_NO_SUCH_OBJECT;
191                         ldap_pvt_thread_mutex_unlock( &passwd_mutex );
192                         goto done;
193                 }
194
195                 e = pw2entry( op->o_bd, pw, &rs->sr_text );
196                 ldap_pvt_thread_mutex_unlock( &passwd_mutex );
197                 if ( !e ) {
198                         rs->sr_err = LDAP_OTHER;
199                         goto done;
200                 }
201
202                 if ( test_filter( op, e, op->oq_search.rs_filter ) == LDAP_COMPARE_TRUE ) {
203                         rs->sr_entry = e;
204                         rs->sr_attrs = op->oq_search.rs_attrs;
205                         send_search_entry( op, rs );
206                 }
207
208                 entry_free( e );
209         }
210
211 done:
212         if( rs->sr_err != LDAP_NO_SUCH_OBJECT ) rs->sr_matched = NULL;
213         send_ldap_result( op, rs );
214
215         if( rdn != NULL ) ldap_rdnfree( rdn );
216
217         return( 0 );
218 }
219
220 static void
221 pw_start(
222         Backend *be
223 )
224 {
225         endpwent();
226
227 #ifdef HAVE_SETPWFILE
228         if ( be->be_private != NULL ) {
229                 (void) setpwfile( (char *) be->be_private );
230         }
231 #endif /* HAVE_SETPWFILE */
232 }
233
234 static Entry *
235 pw2entry( Backend *be, struct passwd *pw, const char **text )
236 {
237         size_t pwlen;
238         Entry           *e;
239         struct berval   vals[2];
240         struct berval   bv;
241
242         int rc;
243
244         AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
245         AttributeDescription *ad_cn = NULL;
246         AttributeDescription *ad_sn = NULL;
247         AttributeDescription *ad_uid = NULL;
248         AttributeDescription *ad_description = NULL;
249
250         rc = slap_str2ad( "cn", &ad_cn, text );
251         if(rc != LDAP_SUCCESS) return NULL;
252         rc = slap_str2ad( "sn", &ad_sn, text );
253         if(rc != LDAP_SUCCESS) return NULL;
254         rc = slap_str2ad( "uid", &ad_uid, text );
255         if(rc != LDAP_SUCCESS) return NULL;
256         rc = slap_str2ad( "description", &ad_description, text );
257         if(rc != LDAP_SUCCESS) return NULL;
258
259         /*
260          * from pw we get pw_name and make it cn
261          * give it an objectclass of person.
262          */
263
264         pwlen = strlen( pw->pw_name );
265         vals[0].bv_len = (sizeof("uid=,")-1) + ( pwlen + be->be_suffix[0].bv_len );
266         vals[0].bv_val = ch_malloc( vals[0].bv_len + 1 );
267
268         /* rdn attribute type should be a configuratable item */
269         sprintf( vals[0].bv_val, "uid=%s,%s",
270                 pw->pw_name, be->be_suffix[0].bv_val );
271
272         rc = dnNormalize( 0, NULL, NULL, vals, &bv, NULL );
273         if( rc != LDAP_SUCCESS ) {
274                 free( vals[0].bv_val );
275                 return NULL;
276         }
277
278         e = (Entry *) ch_calloc( 1, sizeof(Entry) );
279         e->e_name = vals[0];
280         e->e_nname = bv;
281
282         e->e_attrs = NULL;
283
284         vals[1].bv_val = NULL;
285
286         /* objectclasses should be configurable items */
287         vals[0].bv_val = "top";
288         vals[0].bv_len = sizeof("top")-1;
289         attr_mergeit( e, ad_objectClass, vals );
290
291         vals[0].bv_val = "person";
292         vals[0].bv_len = sizeof("person")-1;
293         attr_mergeit( e, ad_objectClass, vals );
294
295         vals[0].bv_val = "uidObject";
296         vals[0].bv_len = sizeof("uidObject")-1;
297         attr_mergeit( e, ad_objectClass, vals );
298
299         vals[0].bv_val = pw->pw_name;
300         vals[0].bv_len = pwlen;
301         attr_mergeit( e, ad_uid, vals );        /* required by uidObject */
302         attr_mergeit( e, ad_cn, vals ); /* required by person */
303         attr_mergeit( e, ad_sn, vals ); /* required by person */
304
305 #ifdef HAVE_PW_GECOS
306         /*
307          * if gecos is present, add it as a cn. first process it
308          * according to standard BSD usage. If the processed cn has
309          * a space, use the tail as the surname.
310          */
311         if (pw->pw_gecos[0]) {
312                 char *s;
313
314                 vals[0].bv_val = pw->pw_gecos;
315                 vals[0].bv_len = strlen(vals[0].bv_val);
316                 attr_mergeit(e, ad_description, vals);
317
318                 s = strchr(vals[0].bv_val, ',');
319                 if (s) *s = '\0';
320
321                 s = strchr(vals[0].bv_val, '&');
322                 if (s) {
323                         char buf[1024];
324
325                         if( vals[0].bv_len + pwlen < sizeof(buf) ) {
326                                 int i = s - vals[0].bv_val;
327                                 strncpy(buf, vals[0].bv_val, i);
328                                 s = buf+i;
329                                 strcpy(s, pw->pw_name);
330                                 *s = TOUPPER((unsigned char)*s);
331                                 strcat(s, vals[0].bv_val+i+1);
332                                 vals[0].bv_val = buf;
333                         }
334                 }
335                 vals[0].bv_len = strlen(vals[0].bv_val);
336
337                 if ( vals[0].bv_len && strcasecmp( vals[0].bv_val, pw->pw_name )) {
338                         attr_mergeit( e, ad_cn, vals );
339                 }
340
341                 if ( (s=strrchr(vals[0].bv_val, ' '))) {
342                         vals[0].bv_val = s + 1;
343                         vals[0].bv_len = strlen(vals[0].bv_val);
344                         attr_mergeit(e, ad_sn, vals);
345                 }
346         }
347 #endif
348
349         return( e );
350 }