/* $NetBSD: shadow.c,v 1.3 2021/08/14 16:14:52 christos Exp $ */
/* shadow.c - shadow account lookup routines */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 2008-2021 The OpenLDAP Foundation.
* Portions Copyright 2008 by Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* .
*/
/* ACKNOWLEDGEMENTS:
* This code references portions of the nss-ldapd package
* written by Arthur de Jong. The nss-ldapd code was forked
* from the nss-ldap library written by Luke Howard.
*/
#include "nssov.h"
/* ( nisSchema.2.1 NAME 'shadowAccount' SUP top AUXILIARY
* DESC 'Additional attributes for shadow passwords'
* MUST uid
* MAY ( userPassword $ shadowLastChange $ shadowMin
* shadowMax $ shadowWarning $ shadowInactive $
* shadowExpire $ shadowFlag $ description ) )
*/
/* the basic search filter for searches */
static struct berval shadow_filter = BER_BVC("(objectClass=shadowAccount)");
/* the attributes to request with searches */
static struct berval shadow_keys[] = {
BER_BVC("uid"),
BER_BVC("userPassword"),
BER_BVC("shadowLastChange"),
BER_BVC("shadowMin"),
BER_BVC("shadowMax"),
BER_BVC("shadowWarning"),
BER_BVC("shadowInactive"),
BER_BVC("shadowExpire"),
BER_BVC("shadowFlag"),
BER_BVNULL
};
#define UID_KEY 0
#define PWD_KEY 1
#define CHG_KEY 2
#define MIN_KEY 3
#define MAX_KEY 4
#define WRN_KEY 5
#define INA_KEY 6
#define EXP_KEY 7
#define FLG_KEY 8
/* default values for attributes */
static struct berval default_shadow_userPassword = BER_BVC("*"); /* unmatchable */
static int default_nums[] = { 0,0,
-1, /* LastChange */
-1, /* Min */
-1, /* Max */
-1, /* Warning */
-1, /* Inactive */
-1, /* Expire */
0 /* Flag */
};
NSSOV_INIT(shadow)
static long to_date(struct berval *date,AttributeDescription *attr)
{
long value;
char *tmp;
/* do some special handling for date values on AD */
if (strcasecmp(attr->ad_cname.bv_val,"pwdLastSet")==0)
{
char buffer[8];
size_t l;
/* we expect an AD 64-bit datetime value;
we should do date=date/864000000000-134774
but that causes problems on 32-bit platforms,
first we divide by 1000000000 by stripping the
last 9 digits from the string and going from there */
l=date->bv_len-9;
if (l<1 || l>(sizeof(buffer)-1))
return 0; /* error */
strncpy(buffer,date->bv_val,l);
buffer[l]='\0';
value=strtol(buffer,&tmp,0);
if ((buffer[0]=='\0')||(*tmp!='\0'))
{
Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n",
attr->ad_cname.bv_val );
return 0;
}
return value/864-134774;
/* note that AD does not have expiry dates but a lastchangeddate
and some value that needs to be added */
}
value=strtol(date->bv_val,&tmp,0);
if ((date->bv_val[0]=='\0')||(*tmp!='\0'))
{
Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n",
attr->ad_cname.bv_val );
return 0;
}
return value;
}
#ifndef UF_DONT_EXPIRE_PASSWD
#define UF_DONT_EXPIRE_PASSWD 0x10000
#endif
#define GET_OPTIONAL_LONG(var,key) \
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \
if ( !a || BER_BVISNULL(&a->a_vals[0])) \
var = default_nums[key]; \
else \
{ \
if (a->a_numvals > 1) \
{ \
Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \
entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val); \
} \
var=strtol(a->a_vals[0].bv_val,&tmp,0); \
if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) \
{ \
Debug(LDAP_DEBUG_ANY,"shadow entry %s contains non-numeric %s value\n", \
entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val); \
return 0; \
} \
}
#define GET_OPTIONAL_DATE(var,key) \
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \
if ( !a || BER_BVISNULL(&a->a_vals[0])) \
var = default_nums[key]; \
else \
{ \
if (a->a_numvals > 1) \
{ \
Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \
entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val); \
} \
var=to_date(&a->a_vals[0],cbp->mi->mi_attrs[key].an_desc); \
}
NSSOV_CBPRIV(shadow,
char buf[256];
struct berval name;);
static int write_shadow(nssov_shadow_cbp *cbp,Entry *entry)
{
struct berval tmparr[2];
struct berval *names;
Attribute *a;
char *tmp;
struct berval passwd = {0};
long lastchangedate;
long mindays;
long maxdays;
long warndays;
long inactdays;
long expiredate;
unsigned long flag;
int i;
int32_t tmpint32;
/* get username */
if (BER_BVISNULL(&cbp->name))
{
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc);
if (!a)
{
Debug(LDAP_DEBUG_ANY,"shadow entry %s does not contain %s value\n",
entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val );
return 0;
}
names = a->a_vals;
}
else
{
names=tmparr;
names[0]=cbp->name;
BER_BVZERO(&names[1]);
}
/* get password */
a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc);
if ( a )
get_userpassword(&a->a_vals[0], &passwd);
if (BER_BVISNULL(&passwd))
passwd=default_shadow_userPassword;
/* get lastchange date */
GET_OPTIONAL_DATE(lastchangedate,CHG_KEY);
/* get mindays */
GET_OPTIONAL_LONG(mindays,MIN_KEY);
/* get maxdays */
GET_OPTIONAL_LONG(maxdays,MAX_KEY);
/* get warndays */
GET_OPTIONAL_LONG(warndays,WRN_KEY);
/* get inactdays */
GET_OPTIONAL_LONG(inactdays,INA_KEY);
/* get expire date */
GET_OPTIONAL_LONG(expiredate,EXP_KEY);
/* get flag */
GET_OPTIONAL_LONG(flag,FLG_KEY);
/* if we're using AD handle the flag specially */
if (strcasecmp(cbp->mi->mi_attrs[CHG_KEY].an_desc->ad_cname.bv_val,"pwdLastSet")==0)
{
if (flag&UF_DONT_EXPIRE_PASSWD)
maxdays=99999;
flag=0;
}
/* write the entries */
for (i=0;!BER_BVISNULL(&names[i]);i++)
{
WRITE_INT32(cbp->fp,NSLCD_RESULT_BEGIN);
WRITE_BERVAL(cbp->fp,&names[i]);
WRITE_BERVAL(cbp->fp,&passwd);
WRITE_INT32(cbp->fp,lastchangedate);
WRITE_INT32(cbp->fp,mindays);
WRITE_INT32(cbp->fp,maxdays);
WRITE_INT32(cbp->fp,warndays);
WRITE_INT32(cbp->fp,inactdays);
WRITE_INT32(cbp->fp,expiredate);
WRITE_INT32(cbp->fp,flag);
}
return 0;
}
NSSOV_CB(shadow)
NSSOV_HANDLE(
shadow,byname,
char fbuf[1024];
struct berval filter = {sizeof(fbuf)};
filter.bv_val = fbuf;
READ_STRING(fp,cbp.buf);,
cbp.name.bv_len = tmpint32;
cbp.name.bv_val = cbp.buf;
Debug(LDAP_DEBUG_ANY,"nssov_shadow_byname(%s)\n",cbp.name.bv_val);,
NSLCD_ACTION_SHADOW_BYNAME,
nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter)
)
NSSOV_HANDLE(
shadow,all,
struct berval filter;
/* no parameters to read */
BER_BVZERO(&cbp.name);,
Debug(LDAP_DEBUG_ANY,"nssov_shadow_all()\n");,
NSLCD_ACTION_SHADOW_ALL,
(filter=cbp.mi->mi_filter,0)
)