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