Back to index

openldap  2.4.31
passwd.c
Go to the documentation of this file.
00001 /* passwd.c - password lookup routines */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * Portions Copyright 2008 by Howard Chu, Symas Corp.
00007  * All rights reserved.
00008  *
00009  * Redistribution and use in source and binary forms, with or without
00010  * modification, are permitted only as authorized by the OpenLDAP
00011  * Public License.
00012  *
00013  * A copy of this license is available in the file LICENSE in the
00014  * top-level directory of the distribution or, alternatively, at
00015  * <http://www.OpenLDAP.org/license.html>.
00016  */
00017 /* ACKNOWLEDGEMENTS:
00018  * This code references portions of the nss-ldapd package
00019  * written by Arthur de Jong. The nss-ldapd code was forked
00020  * from the nss-ldap library written by Luke Howard.
00021  */
00022 
00023 #include "nssov.h"
00024 
00025 /* ( nisSchema.2.0 NAME 'posixAccount' SUP top AUXILIARY
00026  *      DESC 'Abstraction of an account with POSIX attributes'
00027  *      MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
00028  *      MAY ( userPassword $ loginShell $ gecos $ description ) )
00029  */
00030 
00031 /* the basic search filter for searches */
00032 static struct berval passwd_filter = BER_BVC("(objectClass=posixAccount)");
00033 
00034 /* the attributes used in searches */
00035 static struct berval passwd_keys[] = {
00036        BER_BVC("uid"),
00037        BER_BVC("userPassword"),
00038        BER_BVC("uidNumber"),
00039        BER_BVC("gidNumber"),
00040        BER_BVC("gecos"),
00041        BER_BVC("cn"),
00042        BER_BVC("homeDirectory"),
00043        BER_BVC("loginShell"),
00044        BER_BVC("objectClass"),
00045        BER_BVNULL
00046 };
00047 
00048 #define UID_KEY      0
00049 #define       PWD_KEY       1
00050 #define UIDN_KEY     2
00051 #define GIDN_KEY     3
00052 #define GEC_KEY      4
00053 #define CN_KEY       5
00054 #define DIR_KEY      6
00055 #define SHL_KEY      7
00056 
00057 /* default values for attributes */
00058 static struct berval default_passwd_userPassword = BER_BVC("*"); /* unmatchable */
00059 static struct berval default_passwd_homeDirectory       = BER_BVC("");
00060 static struct berval default_passwd_loginShell          = BER_BVC("");
00061 
00062 static struct berval shadow_passwd = BER_BVC("x");
00063 
00064 NSSOV_INIT(passwd)
00065 
00066 /*
00067         Checks to see if the specified name is a valid user name.
00068 
00069         This test is based on the definition from POSIX (IEEE Std 1003.1, 2004, 3.426 User Name
00070         and 3.276 Portable Filename Character Set):
00071         http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_426
00072         http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
00073 
00074         The standard defines user names valid if they contain characters from
00075         the set [A-Za-z0-9._-] where the hyphen should not be used as first
00076         character. As an extension this test allows the dolar '$' sign as the last
00077         character to support Samba special accounts.
00078 */
00079 int isvalidusername(struct berval *bv)
00080 {
00081        int i;
00082        char *name = bv->bv_val;
00083        if ((name==NULL)||(name[0]=='\0'))
00084               return 0;
00085        /* check first character */
00086        if ( ! ( (name[0]>='A' && name[0] <= 'Z') ||
00087                                     (name[0]>='a' && name[0] <= 'z') ||
00088                                     (name[0]>='0' && name[0] <= '9') ||
00089                                     name[0]=='.' || name[0]=='_' ) )
00090               return 0;
00091        /* check other characters */
00092        for (i=1;i<bv->bv_len;i++)
00093        {
00094               if ( name[i]=='$' )
00095               {
00096                      /* if the char is $ we require it to be the last char */
00097                      if (name[i+1]!='\0')
00098                             return 0;
00099               }
00100               else if ( ! ( (name[i]>='A' && name[i] <= 'Z') ||
00101                                                                (name[i]>='a' && name[i] <= 'z') ||
00102                                                                (name[i]>='0' && name[i] <= '9') ||
00103                                                                name[i]=='.' || name[i]=='_'       || name[i]=='-') )
00104                      return 0;
00105        }
00106        /* no test failed so it must be good */
00107        return -1;
00108 }
00109 
00110 /* return 1 on success */
00111 int nssov_dn2uid(Operation *op,nssov_info *ni,struct berval *dn,struct berval *uid)
00112 {
00113        nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
00114        AttributeDescription *ad = mi->mi_attrs[UID_KEY].an_desc;
00115        Entry *e;
00116 
00117        /* check for empty string */
00118        if (!dn->bv_len)
00119               return 0;
00120        /* try to look up uid within DN string */
00121        if (!strncmp(dn->bv_val,ad->ad_cname.bv_val,ad->ad_cname.bv_len) &&
00122               dn->bv_val[ad->ad_cname.bv_len] == '=')
00123        {
00124               struct berval bv, rdn;
00125               dnRdn(dn, &rdn);
00126               /* check if it is valid */
00127               bv.bv_val = dn->bv_val + ad->ad_cname.bv_len + 1;
00128               bv.bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
00129               if (!isvalidusername(&bv))
00130                      return 0;
00131               ber_dupbv_x( uid, &bv, op->o_tmpmemctx );
00132               return 1;
00133        }
00134        /* look up the uid from the entry itself */
00135        if (be_entry_get_rw( op, dn, NULL, ad, 0, &e) == LDAP_SUCCESS)
00136        {
00137               Attribute *a = attr_find(e->e_attrs, ad);
00138               if (a) {
00139                      ber_dupbv_x(uid, &a->a_vals[0], op->o_tmpmemctx);
00140               }
00141               be_entry_release_r(op, e);
00142               if (a)
00143                      return 1;
00144        }
00145        return 0;
00146 }
00147 
00148 int nssov_name2dn_cb(Operation *op,SlapReply *rs)
00149 {
00150        if ( rs->sr_type == REP_SEARCH )
00151        {
00152               struct berval *bv = op->o_callback->sc_private;
00153               if ( !BER_BVISNULL(bv)) {
00154                      op->o_tmpfree( bv->bv_val, op->o_tmpmemctx );
00155                      BER_BVZERO(bv);
00156                      return LDAP_ALREADY_EXISTS;
00157               }
00158               ber_dupbv_x(bv, &rs->sr_entry->e_name, op->o_tmpmemctx);
00159        }
00160        return LDAP_SUCCESS;
00161 }
00162 
00163 int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval *dn)
00164 {
00165        nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
00166        char fbuf[1024];
00167        struct berval filter = {sizeof(fbuf),fbuf};
00168        slap_callback cb = {0};
00169        SlapReply rs = {REP_RESULT};
00170        Operation op2;
00171        int rc;
00172 
00173        /* if it isn't a valid username, just bail out now */
00174        if (!isvalidusername(uid))
00175               return 0;
00176        /* we have to look up the entry */
00177        nssov_filter_byid(mi,UID_KEY,uid,&filter);
00178        BER_BVZERO(dn);
00179        cb.sc_private = dn;
00180        cb.sc_response = nssov_name2dn_cb;
00181        op2 = *op;
00182        op2.o_callback = &cb;
00183        op2.o_req_dn = mi->mi_base;
00184        op2.o_req_ndn = mi->mi_base;
00185        op2.ors_scope = mi->mi_scope;
00186        op2.ors_filterstr = filter;
00187        op2.ors_filter = str2filter_x( op, filter.bv_val );
00188        op2.ors_attrs = slap_anlist_no_attrs;
00189        op2.ors_tlimit = SLAP_NO_LIMIT;
00190        op2.ors_slimit = SLAP_NO_LIMIT;
00191        rc = op2.o_bd->be_search( &op2, &rs );
00192        filter_free_x( op, op2.ors_filter, 1 );
00193        return rc == LDAP_SUCCESS && !BER_BVISNULL(dn);
00194 }
00195 
00196 /* the maximum number of uidNumber attributes per entry */
00197 #define MAXUIDS_PER_ENTRY 5
00198 
00199 NSSOV_CBPRIV(passwd,
00200        char buf[256];
00201        struct berval name;
00202        struct berval id;);
00203 
00204 static struct berval shadowclass = BER_BVC("shadowAccount");
00205 
00206 static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry)
00207 {
00208        int32_t tmpint32;
00209        struct berval tmparr[2], tmpuid[2];
00210        const char **tmpvalues;
00211        char *tmp;
00212        struct berval *names;
00213        struct berval *uids;
00214        struct berval passwd = {0};
00215        gid_t gid;
00216        struct berval gecos;
00217        struct berval homedir;
00218        struct berval shell;
00219        Attribute *a;
00220        int i,j;
00221        int use_shadow = 0;
00222        /* get the usernames for this entry */
00223        if (BER_BVISNULL(&cbp->name))
00224        {
00225               a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
00226               if (!a)
00227               {
00228                      Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n",
00229                             entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0);
00230                      return 0;
00231               }
00232               names = a->a_vals;
00233        }
00234        else
00235        {
00236               names=tmparr;
00237               names[0]=cbp->name;
00238               BER_BVZERO(&names[1]);
00239        }
00240        /* get the password for this entry */
00241        a = attr_find(entry->e_attrs, slap_schema.si_ad_objectClass);
00242        if ( a ) {
00243               for ( i=0; i<a->a_numvals; i++) {
00244                      if ( bvmatch( &shadowclass, &a->a_nvals[i] )) {
00245                             use_shadow = 1;
00246                             break;
00247                      }
00248               }
00249        }
00250        if ( use_shadow )
00251        {
00252               /* if the entry has a shadowAccount entry, point to that instead */
00253               passwd = shadow_passwd;
00254        }
00255        else
00256        {
00257               a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
00258               if (a)
00259                      get_userpassword(&a->a_vals[0], &passwd);
00260               if (BER_BVISNULL(&passwd))
00261                      passwd=default_passwd_userPassword;
00262        }
00263        /* get the uids for this entry */
00264        if (BER_BVISNULL(&cbp->id))
00265        {
00266               a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UIDN_KEY].an_desc);
00267         if ( !a )
00268               {
00269                      Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n",
00270                             entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val,0);
00271                      return 0;
00272               }
00273               uids = a->a_vals;
00274        }
00275        else
00276        {
00277               uids = tmpuid;
00278               uids[0] = cbp->id;
00279               BER_BVZERO(&uids[1]);
00280        }
00281        /* get the gid for this entry */
00282        a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GIDN_KEY].an_desc);
00283        if (!a)
00284        {
00285               Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n",
00286                      entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0);
00287               return 0;
00288        }
00289        else if (a->a_numvals != 1)
00290        {
00291               Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n",
00292                      entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0);
00293        }
00294        gid=(gid_t)strtol(a->a_vals[0].bv_val,&tmp,0);
00295        if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0'))
00296        {
00297               Debug(LDAP_DEBUG_ANY,"passwd entry %s contains non-numeric %s value\n",
00298                      entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0);
00299               return 0;
00300        }
00301        /* get the gecos for this entry (fall back to cn) */
00302        a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GEC_KEY].an_desc);
00303        if (!a)
00304               a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc);
00305        if (!a || !a->a_numvals)
00306        {
00307               Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s or %s value\n",
00308                      entry->e_name.bv_val,
00309                      cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val,
00310                      cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val);
00311               return 0;
00312        }
00313        else if (a->a_numvals > 1)
00314        {
00315               Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s or %s values\n",
00316                      entry->e_name.bv_val,
00317                      cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val,
00318                      cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val);
00319        }
00320        gecos=a->a_vals[0];
00321        /* get the home directory for this entry */
00322        a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[DIR_KEY].an_desc);
00323        if (!a)
00324        {
00325               Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n",
00326                      entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0);
00327               homedir=default_passwd_homeDirectory;
00328        }
00329        else
00330        {
00331               if (a->a_numvals > 1)
00332               {
00333                      Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n",
00334                             entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0);
00335               }
00336               homedir=a->a_vals[0];
00337               if (homedir.bv_val[0]=='\0')
00338                      homedir=default_passwd_homeDirectory;
00339        }
00340        /* get the shell for this entry */
00341        a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[SHL_KEY].an_desc);
00342        if (!a)
00343        {
00344               shell=default_passwd_loginShell;
00345        }
00346        else
00347        {
00348               if (a->a_numvals > 1)
00349               {
00350                      Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n",
00351                             entry->e_name.bv_val, cbp->mi->mi_attrs[SHL_KEY].an_desc->ad_cname.bv_val,0);
00352               }
00353               shell=a->a_vals[0];
00354               if (shell.bv_val[0]=='\0')
00355                      shell=default_passwd_loginShell;
00356        }
00357        /* write the entries */
00358        for (i=0;!BER_BVISNULL(&names[i]);i++)
00359        {
00360               if (!isvalidusername(&names[i]))
00361               {
00362                      Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains invalid user name: \"%s\"\n",
00363                             entry->e_name.bv_val,names[i].bv_val,0);
00364               }
00365               else
00366               {
00367                      for (j=0;!BER_BVISNULL(&uids[j]);j++)
00368                      {
00369                             char *tmp;
00370                             uid_t uid;
00371                             uid = strtol(uids[j].bv_val, &tmp, 0);
00372                             if ( *tmp ) {
00373                                    Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains non-numeric %s value: \"%s\"\n",
00374                                           entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val,
00375                                           names[i].bv_val);
00376                                    continue;
00377                             }
00378                             WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN);
00379                             WRITE_BERVAL(cbp->fp,&names[i]);
00380                             WRITE_BERVAL(cbp->fp,&passwd);
00381                             WRITE_TYPE(cbp->fp,uid,uid_t);
00382                             WRITE_TYPE(cbp->fp,gid,gid_t);
00383                             WRITE_BERVAL(cbp->fp,&gecos);
00384                             WRITE_BERVAL(cbp->fp,&homedir);
00385                             WRITE_BERVAL(cbp->fp,&shell);
00386                      }
00387               }
00388        }
00389        return 0;
00390 }
00391 
00392 NSSOV_CB(passwd)
00393 
00394 NSSOV_HANDLE(
00395        passwd,byname,
00396        char fbuf[1024];
00397        struct berval filter = {sizeof(fbuf)};
00398        filter.bv_val = fbuf;
00399        READ_STRING(fp,cbp.buf);
00400        cbp.name.bv_len = tmpint32;
00401        cbp.name.bv_val = cbp.buf;
00402        if (!isvalidusername(&cbp.name)) {
00403               Debug(LDAP_DEBUG_ANY,"nssov_passwd_byname(%s): invalid user name\n",cbp.name.bv_val,0,0);
00404               return -1;
00405        }
00406        BER_BVZERO(&cbp.id); ,
00407        Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byname(%s)\n",cbp.name.bv_val,0,0);,
00408        NSLCD_ACTION_PASSWD_BYNAME,
00409        nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter)
00410 )
00411 
00412 NSSOV_HANDLE(
00413        passwd,byuid,
00414        uid_t uid;
00415        char fbuf[1024];
00416        struct berval filter = {sizeof(fbuf)};
00417        filter.bv_val = fbuf;
00418        READ_TYPE(fp,uid,uid_t);
00419        cbp.id.bv_val = cbp.buf;
00420        cbp.id.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",uid);
00421        BER_BVZERO(&cbp.name);,
00422        Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byuid(%s)\n",cbp.id.bv_val,0,0);,
00423        NSLCD_ACTION_PASSWD_BYUID,
00424        nssov_filter_byid(cbp.mi,UIDN_KEY,&cbp.id,&filter)
00425 )
00426 
00427 NSSOV_HANDLE(
00428        passwd,all,
00429        struct berval filter;
00430        /* no parameters to read */
00431        BER_BVZERO(&cbp.name);
00432        BER_BVZERO(&cbp.id);,
00433        Debug(LDAP_DEBUG_TRACE,"nssov_passwd_all()\n",0,0,0);,
00434        NSLCD_ACTION_PASSWD_ALL,
00435        (filter=cbp.mi->mi_filter,0)
00436 )