1 /* $NetBSD: shadow.c,v 1.3 2021/08/14 16:14:52 christos 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-2021 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
NSSOV_INIT(shadow)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 divide 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 );
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 );
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); \
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); \
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); \
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
write_shadow(nssov_shadow_cbp * cbp,Entry * entry)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 );
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);,
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");,
257 NSLCD_ACTION_SHADOW_ALL,
258 (filter=cbp.mi->mi_filter,0)
259 )
260