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