xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/nssov/shadow.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
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