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