Back to index

openldap  2.4.31
search.c
Go to the documentation of this file.
00001 /* search.c - /etc/passwd backend search function */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00017  * All rights reserved.
00018  *
00019  * Redistribution and use in source and binary forms are permitted
00020  * provided that this notice is preserved and that due credit is given
00021  * to the University of Michigan at Ann Arbor. The name of the University
00022  * may not be used to endorse or promote products derived from this
00023  * software without specific prior written permission. This software
00024  * is provided ``as is'' without express or implied warranty.
00025  */
00026 /* ACKNOWLEDGEMENTS:
00027  * This work was originally developed by the University of Michigan
00028  * (as part of U-MICH LDAP).  Additional significant contributors
00029  * include:
00030  *     Hallvard B. Furuseth
00031  *     Howard Chu
00032  *     Kurt D. Zeilenga
00033  */
00034 
00035 #include "portable.h"
00036 
00037 #include <stdio.h>
00038 
00039 #include <ac/ctype.h>
00040 #include <ac/socket.h>
00041 #include <ac/string.h>
00042 #include <ac/time.h>
00043 
00044 #include <pwd.h>
00045 
00046 #include "slap.h"
00047 #include "back-passwd.h"
00048 
00049 static void pw_start( Backend *be );
00050 
00051 static int pw2entry(
00052        Backend              *be,
00053        struct passwd *pw,
00054        Entry         *ep );
00055 
00056 int
00057 passwd_back_search(
00058     Operation *op,
00059     SlapReply *rs )
00060 {
00061        struct passwd *pw;
00062        time_t        stoptime = (time_t)-1;
00063 
00064        LDAPRDN rdn = NULL;
00065        struct berval parent = BER_BVNULL;
00066 
00067        AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
00068 
00069        if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
00070               stoptime = op->o_time + op->ors_tlimit;
00071        }
00072 
00073        /* Handle a query for the base of this backend */
00074        if ( be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
00075               struct berval val;
00076 
00077               rs->sr_matched = op->o_req_dn.bv_val;
00078 
00079               if( op->ors_scope != LDAP_SCOPE_ONELEVEL ) {
00080                      AttributeDescription *desc = NULL;
00081                      char                 *next;
00082                      Entry                e = { 0 };
00083 
00084                      /* Create an entry corresponding to the base DN */
00085                      e.e_name.bv_val = ch_strdup( op->o_req_dn.bv_val );
00086                      e.e_name.bv_len = op->o_req_dn.bv_len;
00087                      e.e_nname.bv_val =  ch_strdup( op->o_req_ndn.bv_val );
00088                      e.e_nname.bv_len = op->o_req_ndn.bv_len;
00089 
00090                      /* Use the first attribute of the DN
00091                      * as an attribute within the entry itself.
00092                      */
00093                      if( ldap_bv2rdn( &op->o_req_dn, &rdn, &next, 
00094                             LDAP_DN_FORMAT_LDAP ) )
00095                      {
00096                             rs->sr_err = LDAP_INVALID_DN_SYNTAX;
00097                             goto done;
00098                      }
00099 
00100                      if( slap_bv2ad( &rdn[0]->la_attr, &desc, &rs->sr_text )) {
00101                             rs->sr_err = LDAP_NO_SUCH_OBJECT;
00102                             ldap_rdnfree(rdn);
00103                             goto done;
00104                      }
00105 
00106                      attr_merge_normalize_one( &e, desc, &rdn[0]->la_value, NULL );
00107 
00108                      ldap_rdnfree(rdn);
00109                      rdn = NULL;
00110 
00111                      /* Every entry needs an objectclass. We don't really
00112                       * know if our hardcoded choice here agrees with the
00113                       * DN that was configured for this backend, but it's
00114                       * better than nothing.
00115                       *
00116                       * should be a configuratable item
00117                       */
00118                      BER_BVSTR( &val, "organizationalUnit" );
00119                      attr_merge_one( &e, ad_objectClass, &val, NULL );
00120        
00121                      if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
00122                             rs->sr_entry = &e;
00123                             rs->sr_attrs = op->ors_attrs;
00124                             rs->sr_flags = REP_ENTRY_MODIFIABLE;
00125                             send_search_entry( op, rs );
00126                             rs->sr_flags = 0;
00127                             rs->sr_attrs = NULL;
00128                      }
00129 
00130                      entry_clean( &e );
00131               }
00132 
00133               if ( op->ors_scope != LDAP_SCOPE_BASE ) {
00134                      /* check all our "children" */
00135 
00136                      ldap_pvt_thread_mutex_lock( &passwd_mutex );
00137                      pw_start( op->o_bd );
00138                      for ( pw = getpwent(); pw != NULL; pw = getpwent() ) {
00139                             Entry         e = { 0 };
00140 
00141                             /* check for abandon */
00142                             if ( op->o_abandon ) {
00143                                    endpwent();
00144                                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00145                                    return( SLAPD_ABANDON );
00146                             }
00147 
00148                             /* check time limit */
00149                             if ( op->ors_tlimit != SLAP_NO_LIMIT
00150                                           && slap_get_time() > stoptime )
00151                             {
00152                                    send_ldap_error( op, rs, LDAP_TIMELIMIT_EXCEEDED, NULL );
00153                                    endpwent();
00154                                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00155                                    return( 0 );
00156                             }
00157 
00158                             if ( pw2entry( op->o_bd, pw, &e ) ) {
00159                                    rs->sr_err = LDAP_OTHER;
00160                                    endpwent();
00161                                    ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00162                                    goto done;
00163                             }
00164 
00165                             if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
00166                                    /* check size limit */
00167                                    if ( --op->ors_slimit == -1 ) {
00168                                           send_ldap_error( op, rs, LDAP_SIZELIMIT_EXCEEDED, NULL );
00169                                           endpwent();
00170                                           ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00171                                           return( 0 );
00172                                    }
00173 
00174                                    rs->sr_entry = &e;
00175                                    rs->sr_attrs = op->ors_attrs;
00176                                    rs->sr_flags = REP_ENTRY_MODIFIABLE;
00177                                    send_search_entry( op, rs );
00178                                    rs->sr_flags = 0;
00179                                    rs->sr_entry = NULL;
00180                             }
00181 
00182                             entry_clean( &e );
00183                      }
00184                      endpwent();
00185                      ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00186               }
00187 
00188        } else {
00189               char   *next;
00190               Entry  e = { 0 };
00191               int    rc;
00192 
00193               if (! be_issuffix( op->o_bd, &op->o_req_ndn ) ) {
00194                      dnParent( &op->o_req_ndn, &parent );
00195               }
00196 
00197               /* This backend is only one layer deep. Don't answer requests for
00198                * anything deeper than that.
00199                */
00200               if( !be_issuffix( op->o_bd, &parent ) ) {
00201                      int i;
00202                      for( i=0; op->o_bd->be_nsuffix[i].bv_val != NULL; i++ ) {
00203                             if( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_nsuffix[i] ) ) {
00204                                    rs->sr_matched = op->o_bd->be_suffix[i].bv_val;
00205                                    break;
00206                             }
00207                      }
00208                      rs->sr_err = LDAP_NO_SUCH_OBJECT;
00209                      goto done;
00210               }
00211 
00212               if( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
00213                      goto done;
00214               }
00215 
00216               if ( ldap_bv2rdn( &op->o_req_dn, &rdn, &next,
00217                      LDAP_DN_FORMAT_LDAP ))
00218               { 
00219                      rs->sr_err = LDAP_OTHER;
00220                      goto done;
00221               }
00222 
00223               ldap_pvt_thread_mutex_lock( &passwd_mutex );
00224               pw_start( op->o_bd );
00225               pw = getpwnam( rdn[0]->la_value.bv_val );
00226               if ( pw == NULL ) {
00227                      rs->sr_matched = parent.bv_val;
00228                      rs->sr_err = LDAP_NO_SUCH_OBJECT;
00229                      ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00230                      goto done;
00231               }
00232 
00233               rc = pw2entry( op->o_bd, pw, &e );
00234               ldap_pvt_thread_mutex_unlock( &passwd_mutex );
00235               if ( rc ) {
00236                      rs->sr_err = LDAP_OTHER;
00237                      goto done;
00238               }
00239 
00240               if ( test_filter( op, &e, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
00241                      rs->sr_entry = &e;
00242                      rs->sr_attrs = op->ors_attrs;
00243                      rs->sr_flags = REP_ENTRY_MODIFIABLE;
00244                      send_search_entry( op, rs );
00245                      rs->sr_flags = 0;
00246                      rs->sr_entry = NULL;
00247                      rs->sr_attrs = NULL;
00248               }
00249 
00250               entry_clean( &e );
00251        }
00252 
00253 done:
00254        if( rs->sr_err != LDAP_NO_SUCH_OBJECT ) rs->sr_matched = NULL;
00255        send_ldap_result( op, rs );
00256 
00257        if( rdn != NULL ) ldap_rdnfree( rdn );
00258 
00259        return( 0 );
00260 }
00261 
00262 static void
00263 pw_start(
00264        Backend *be
00265 )
00266 {
00267        endpwent();
00268 
00269 #ifdef HAVE_SETPWFILE
00270        if ( be->be_private != NULL ) {
00271               (void) setpwfile( (char *) be->be_private );
00272        }
00273 #endif /* HAVE_SETPWFILE */
00274 }
00275 
00276 static int
00277 pw2entry( Backend *be, struct passwd *pw, Entry *e )
00278 {
00279        size_t        pwlen;
00280        struct berval val;
00281        struct berval bv;
00282 
00283        int           rc;
00284 
00285        /*
00286         * from pw we get pw_name and make it cn
00287         * give it an objectclass of person.
00288         */
00289 
00290        pwlen = strlen( pw->pw_name );
00291        val.bv_len = STRLENOF("uid=,") + ( pwlen + be->be_suffix[0].bv_len );
00292        val.bv_val = ch_malloc( val.bv_len + 1 );
00293 
00294        /* rdn attribute type should be a configuratable item */
00295        sprintf( val.bv_val, "uid=%s,%s",
00296               pw->pw_name, be->be_suffix[0].bv_val );
00297 
00298        rc = dnNormalize( 0, NULL, NULL, &val, &bv, NULL );
00299        if( rc != LDAP_SUCCESS ) {
00300               free( val.bv_val );
00301               return( -1 );
00302        }
00303 
00304        e->e_name = val;
00305        e->e_nname = bv;
00306 
00307        e->e_attrs = NULL;
00308 
00309        /* objectclasses should be configurable items */
00310        BER_BVSTR( &val, "person" );
00311        attr_merge_one( e, slap_schema.si_ad_objectClass, &val, NULL );
00312 
00313        BER_BVSTR( &val, "uidObject" );
00314        attr_merge_one( e, slap_schema.si_ad_objectClass, &val, NULL );
00315 
00316        val.bv_val = pw->pw_name;
00317        val.bv_len = pwlen;
00318        attr_merge_normalize_one( e, slap_schema.si_ad_uid, &val, NULL );     /* required by uidObject */
00319        attr_merge_normalize_one( e, slap_schema.si_ad_cn, &val, NULL );      /* required by person */
00320        attr_merge_normalize_one( e, ad_sn, &val, NULL );       /* required by person */
00321 
00322 #ifdef HAVE_STRUCT_PASSWD_PW_GECOS
00323        /*
00324         * if gecos is present, add it as a cn. first process it
00325         * according to standard BSD usage. If the processed cn has
00326         * a space, use the tail as the surname.
00327         */
00328        if (pw->pw_gecos[0]) {
00329               char *s;
00330 
00331               ber_str2bv( pw->pw_gecos, 0, 0, &val );
00332               attr_merge_normalize_one( e, ad_desc, &val, NULL );
00333 
00334               s = ber_bvchr( &val, ',' );
00335               if ( s ) *s = '\0';
00336 
00337               s = ber_bvchr( &val, '&' );
00338               if ( s ) {
00339                      char buf[1024];
00340 
00341                      if( val.bv_len + pwlen < sizeof(buf) ) {
00342                             int i = s - val.bv_val;
00343                             strncpy( buf, val.bv_val, i );
00344                             s = buf + i;
00345                             strcpy( s, pw->pw_name );
00346                             *s = TOUPPER((unsigned char)*s);
00347                             strcat( s, val.bv_val + i + 1 );
00348                             val.bv_val = buf;
00349                      }
00350               }
00351               val.bv_len = strlen( val.bv_val );
00352 
00353               if ( val.bv_len && strcasecmp( val.bv_val, pw->pw_name ) ) {
00354                      attr_merge_normalize_one( e, slap_schema.si_ad_cn, &val, NULL );
00355               }
00356 
00357               if ( ( s = strrchr(val.bv_val, ' ' ) ) ) {
00358                      ber_str2bv( s + 1, 0, 0, &val );
00359                      attr_merge_normalize_one( e, ad_sn, &val, NULL );
00360               }
00361        }
00362 #endif /* HAVE_STRUCT_PASSWD_PW_GECOS */
00363 
00364        return( 0 );
00365 }