1 /* shadow.c - shadow account lookup routines */ 2 /* $OpenLDAP: pkg/ldap/contrib/slapd-modules/nssov/shadow.c,v 1.1.2.1 2008/07/08 18:53:58 quanah Exp $ */ 3 /* 4 * Copyright 2008 by Howard Chu, Symas Corp. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted only as authorized by the OpenLDAP 9 * Public License. 10 * 11 * A copy of this license is available in the file LICENSE in the 12 * top-level directory of the distribution or, alternatively, at 13 * <http://www.OpenLDAP.org/license.html>. 14 */ 15 /* 16 * This code references portions of the nss-ldapd package 17 * written by Arthur de Jong. The nss-ldapd code was forked 18 * from the nss-ldap library written by Luke Howard. 19 */ 20 21 #include "nssov.h" 22 23 /* ( nisSchema.2.1 NAME 'shadowAccount' SUP top AUXILIARY 24 * DESC 'Additional attributes for shadow passwords' 25 * MUST uid 26 * MAY ( userPassword $ shadowLastChange $ shadowMin 27 * shadowMax $ shadowWarning $ shadowInactive $ 28 * shadowExpire $ shadowFlag $ description ) ) 29 */ 30 31 /* the basic search filter for searches */ 32 static struct berval shadow_filter = BER_BVC("(objectClass=shadowAccount)"); 33 34 /* the attributes to request with searches */ 35 static struct berval shadow_keys[] = { 36 BER_BVC("uid"), 37 BER_BVC("userPassword"), 38 BER_BVC("shadowLastChange"), 39 BER_BVC("shadowMin"), 40 BER_BVC("shadowMax"), 41 BER_BVC("shadowWarning"), 42 BER_BVC("shadowInactive"), 43 BER_BVC("shadowExpire"), 44 BER_BVC("shadowFlag"), 45 BER_BVNULL 46 }; 47 48 #define UID_KEY 0 49 #define PWD_KEY 1 50 #define CHG_KEY 2 51 #define MIN_KEY 3 52 #define MAX_KEY 4 53 #define WRN_KEY 5 54 #define INA_KEY 6 55 #define EXP_KEY 7 56 #define FLG_KEY 8 57 58 /* default values for attributes */ 59 static struct berval default_shadow_userPassword = BER_BVC("*"); /* unmatchable */ 60 static int default_nums[] = { 0,0, 61 -1, /* LastChange */ 62 -1, /* Min */ 63 -1, /* Max */ 64 -1, /* Warning */ 65 -1, /* Inactive */ 66 -1, /* Expire */ 67 0 /* Flag */ 68 }; 69 70 NSSOV_INIT(shadow) 71 72 static long to_date(struct berval *date,AttributeDescription *attr) 73 { 74 long value; 75 char *tmp; 76 /* do some special handling for date values on AD */ 77 if (strcasecmp(attr->ad_cname.bv_val,"pwdLastSet")==0) 78 { 79 char buffer[8]; 80 size_t l; 81 /* we expect an AD 64-bit datetime value; 82 we should do date=date/864000000000-134774 83 but that causes problems on 32-bit platforms, 84 first we devide by 1000000000 by stripping the 85 last 9 digits from the string and going from there */ 86 l=date->bv_len-9; 87 if (l<1 || l>(sizeof(buffer)-1)) 88 return 0; /* error */ 89 strncpy(buffer,date->bv_val,l); 90 buffer[l]='\0'; 91 value=strtol(buffer,&tmp,0); 92 if ((buffer[0]=='\0')||(*tmp!='\0')) 93 { 94 Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value", 95 attr->ad_cname.bv_val,0,0); 96 return 0; 97 } 98 return value/864-134774; 99 /* note that AD does not have expiry dates but a lastchangeddate 100 and some value that needs to be added */ 101 } 102 value=strtol(date->bv_val,&tmp,0); 103 if ((date->bv_val[0]=='\0')||(*tmp!='\0')) 104 { 105 Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value", 106 attr->ad_cname.bv_val,0,0); 107 return 0; 108 } 109 return value; 110 } 111 112 #ifndef UF_DONT_EXPIRE_PASSWD 113 #define UF_DONT_EXPIRE_PASSWD 0x10000 114 #endif 115 116 #define GET_OPTIONAL_LONG(var,key) \ 117 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \ 118 if ( !a || BER_BVISNULL(&a->a_vals[0])) \ 119 var = default_nums[key]; \ 120 else \ 121 { \ 122 if (a->a_numvals > 1) \ 123 { \ 124 Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values", \ 125 entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ 126 } \ 127 var=strtol(a->a_vals[0].bv_val,&tmp,0); \ 128 if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) \ 129 { \ 130 Debug(LDAP_DEBUG_ANY,"shadow entry %s contains non-numeric %s value", \ 131 entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ 132 return 0; \ 133 } \ 134 } 135 136 #define GET_OPTIONAL_DATE(var,key) \ 137 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[key].an_desc); \ 138 if ( !a || BER_BVISNULL(&a->a_vals[0])) \ 139 var = default_nums[key]; \ 140 else \ 141 { \ 142 if (a->a_numvals > 1) \ 143 { \ 144 Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values", \ 145 entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ 146 } \ 147 var=to_date(&a->a_vals[0],cbp->mi->mi_attrs[key].an_desc); \ 148 } 149 150 NSSOV_CBPRIV(shadow, 151 char buf[256]; 152 struct berval name;); 153 154 static int write_shadow(nssov_shadow_cbp *cbp,Entry *entry) 155 { 156 struct berval tmparr[2]; 157 struct berval *names; 158 Attribute *a; 159 char *tmp; 160 struct berval passwd = {0}; 161 long lastchangedate; 162 long mindays; 163 long maxdays; 164 long warndays; 165 long inactdays; 166 long expiredate; 167 unsigned long flag; 168 int i; 169 int32_t tmpint32; 170 /* get username */ 171 if (BER_BVISNULL(&cbp->name)) 172 { 173 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); 174 if (!a) 175 { 176 Debug(LDAP_DEBUG_ANY,"shadow entry %s does not contain %s value", 177 entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0); 178 return 0; 179 } 180 names = a->a_vals; 181 } 182 else 183 { 184 names=tmparr; 185 names[0]=cbp->name; 186 BER_BVZERO(&names[1]); 187 } 188 /* get password */ 189 a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[PWD_KEY].an_desc); 190 if ( a ) 191 get_userpassword(&a->a_vals[0], &passwd); 192 if (BER_BVISNULL(&passwd)) 193 passwd=default_shadow_userPassword; 194 /* get lastchange date */ 195 GET_OPTIONAL_DATE(lastchangedate,CHG_KEY); 196 /* get mindays */ 197 GET_OPTIONAL_LONG(mindays,MIN_KEY); 198 /* get maxdays */ 199 GET_OPTIONAL_LONG(maxdays,MAX_KEY); 200 /* get warndays */ 201 GET_OPTIONAL_LONG(warndays,WRN_KEY); 202 /* get inactdays */ 203 GET_OPTIONAL_LONG(inactdays,INA_KEY); 204 /* get expire date */ 205 GET_OPTIONAL_LONG(expiredate,EXP_KEY); 206 /* get flag */ 207 GET_OPTIONAL_LONG(flag,FLG_KEY); 208 /* if we're using AD handle the flag specially */ 209 if (strcasecmp(cbp->mi->mi_attrs[CHG_KEY].an_desc->ad_cname.bv_val,"pwdLastSet")==0) 210 { 211 if (flag&UF_DONT_EXPIRE_PASSWD) 212 maxdays=99999; 213 flag=0; 214 } 215 /* write the entries */ 216 for (i=0;!BER_BVISNULL(&names[i]);i++) 217 { 218 WRITE_INT32(cbp->fp,NSLCD_RESULT_SUCCESS); 219 WRITE_BERVAL(cbp->fp,&names[i]); 220 WRITE_BERVAL(cbp->fp,&passwd); 221 WRITE_INT32(cbp->fp,lastchangedate); 222 WRITE_INT32(cbp->fp,mindays); 223 WRITE_INT32(cbp->fp,maxdays); 224 WRITE_INT32(cbp->fp,warndays); 225 WRITE_INT32(cbp->fp,inactdays); 226 WRITE_INT32(cbp->fp,expiredate); 227 WRITE_INT32(cbp->fp,flag); 228 } 229 return 0; 230 } 231 232 NSSOV_CB(shadow) 233 234 NSSOV_HANDLE( 235 shadow,byname, 236 char fbuf[1024]; 237 struct berval filter = {sizeof(fbuf)}; 238 filter.bv_val = fbuf; 239 READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));, 240 cbp.name.bv_len = tmpint32; 241 cbp.name.bv_val = cbp.buf; 242 Debug(LDAP_DEBUG_ANY,"nssov_shadow_byname(%s)",cbp.name.bv_val,0,0);, 243 NSLCD_ACTION_SHADOW_BYNAME, 244 nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter) 245 ) 246 247 NSSOV_HANDLE( 248 shadow,all, 249 struct berval filter; 250 /* no parameters to read */ 251 BER_BVZERO(&cbp.name);, 252 Debug(LDAP_DEBUG_ANY,"nssov_shadow_all()",0,0,0);, 253 NSLCD_ACTION_SHADOW_ALL, 254 (filter=cbp.mi->mi_filter,0) 255 ) 256