xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/nssov/pam.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: pam.c,v 1.3 2021/08/14 16:14:52 christos Exp $	*/
2 
3 /* pam.c - pam processing 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  * Portions Copyright 2013 by Ted C. Cheng, Symas Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 
21 #include "nssov.h"
22 #include "lutil.h"
23 
24 #undef ldap_debug	/* silence a warning in ldap-int.h */
25 #include "../../../libraries/libldap/ldap-int.h"	/* for ldap_ld_free */
26 
27 static int ppolicy_cid;
28 static AttributeDescription *ad_loginStatus;
29 
30 struct paminfo {
31 	struct berval uid;
32 	struct berval dn;
33 	struct berval svc;
34 	struct berval ruser;
35 	struct berval rhost;
36 	struct berval tty;
37 	struct berval pwd;
38 	int authz;
39 	struct berval msg;
40 	int ispwdmgr;
41 };
42 
pam_bindcb(Operation * op,SlapReply * rs)43 static int pam_bindcb(
44 	Operation *op, SlapReply *rs)
45 {
46 	struct paminfo *pi = op->o_callback->sc_private;
47 	LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
48 		rs->sr_ctrls, NULL);
49 	if (ctrl) {
50 		LDAP *ld;
51 		ber_int_t expire, grace;
52 		LDAPPasswordPolicyError error;
53 
54 		ldap_create(&ld);
55 		if (ld) {
56 			int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
57 				&expire,&grace,&error);
58 			if (rc == LDAP_SUCCESS) {
59 				if (expire >= 0) {
60 					char *unit = "seconds";
61 					if (expire > 60) {
62 						expire /= 60;
63 						unit = "minutes";
64 					}
65 					if (expire > 60) {
66 						expire /= 60;
67 						unit = "hours";
68 					}
69 					if (expire > 24) {
70 						expire /= 24;
71 						unit = "days";
72 					}
73 #if 0	/* Who warns about expiration so far in advance? */
74 					if (expire > 7) {
75 						expire /= 7;
76 						unit = "weeks";
77 					}
78 					if (expire > 4) {
79 						expire /= 4;
80 						unit = "months";
81 					}
82 					if (expire > 12) {
83 						expire /= 12;
84 						unit = "years";
85 					}
86 #endif
87 					pi->msg.bv_len = sprintf(pi->msg.bv_val,
88 						"\nWARNING: Password expires in %d %s\n", expire, unit);
89 				} else if (grace > 0) {
90 					pi->msg.bv_len = sprintf(pi->msg.bv_val,
91 						"Password expired; %d grace logins remaining",
92 						grace);
93 					pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
94 				} else if (error != PP_noError) {
95 					ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
96 						&pi->msg);
97 					switch (error) {
98 					case PP_passwordExpired:
99 						/* report this during authz */
100 						rs->sr_err = LDAP_SUCCESS;
101 						/* fallthru */
102 					case PP_changeAfterReset:
103 						pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
104 					}
105 				}
106 			}
107 			ldap_ld_free(ld,0,NULL,NULL);
108 		}
109 	}
110 	return LDAP_SUCCESS;
111 }
112 
pam_uid2dn(nssov_info * ni,Operation * op,struct paminfo * pi)113 static int pam_uid2dn(nssov_info *ni, Operation *op,
114 	struct paminfo *pi)
115 {
116 	struct berval sdn;
117 
118 	BER_BVZERO(&pi->dn);
119 
120 	if (!isvalidusername(&pi->uid)) {
121 		Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n",
122 			pi->uid.bv_val ? pi->uid.bv_val : "NULL" );
123 		return NSLCD_PAM_USER_UNKNOWN;
124 	}
125 
126 	if (ni->ni_pam_opts & NI_PAM_SASL2DN) {
127 		int hlen = global_host_bv.bv_len;
128 
129 		/* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
130 		sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen +
131 			STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
132 		sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
133 		sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth",
134 			pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val);
135 		slap_sasl2dn(op, &sdn, &pi->dn, 0);
136 		op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
137 	}
138 
139 	/* If no luck, do a basic uid search */
140 	if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
141 		nssov_uid2dn(op, ni, &pi->uid, &pi->dn);
142 		if (!BER_BVISEMPTY(&pi->dn)) {
143 			sdn = pi->dn;
144 			dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx );
145 		}
146 	}
147 	if (BER_BVISEMPTY(&pi->dn)) {
148 		return NSLCD_PAM_USER_UNKNOWN;
149 	}
150 	return 0;
151 }
152 
pam_do_bind(nssov_info * ni,TFILE * fp,Operation * op,struct paminfo * pi)153 int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
154 	struct paminfo *pi)
155 {
156 	int rc;
157 	slap_callback cb = {0};
158 	SlapReply rs = {REP_RESULT};
159 
160 	pi->msg.bv_val = pi->pwd.bv_val;
161 	pi->msg.bv_len = 0;
162 	pi->authz = NSLCD_PAM_SUCCESS;
163 
164 	if (!pi->ispwdmgr) {
165 
166 		rc = pam_uid2dn(ni, op, pi);
167 		if (rc) goto finish;
168 
169 		if (BER_BVISEMPTY(&pi->pwd)) {
170 			rc = NSLCD_PAM_PERM_DENIED;
171 			goto finish;
172 		}
173 
174 		/* Should only need to do this once at open time, but there's always
175 		 * the possibility that ppolicy will get loaded later.
176 		 */
177 		if (!ppolicy_cid) {
178 			rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
179 				&ppolicy_cid);
180 		}
181 		/* of course, 0 is a valid cid, but it won't be ppolicy... */
182 		if (ppolicy_cid) {
183 			op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
184 		}
185 	}
186 
187 	cb.sc_response = pam_bindcb;
188 	cb.sc_private = pi;
189 	op->o_callback = &cb;
190 	op->o_dn.bv_val[0] = 0;
191 	op->o_dn.bv_len = 0;
192 	op->o_ndn.bv_val[0] = 0;
193 	op->o_ndn.bv_len = 0;
194 	op->o_tag = LDAP_REQ_BIND;
195 	op->o_protocol = LDAP_VERSION3;
196 	op->orb_method = LDAP_AUTH_SIMPLE;
197 	op->orb_cred = pi->pwd;
198 	op->o_req_dn = pi->dn;
199 	op->o_req_ndn = pi->dn;
200 	slap_op_time( &op->o_time, &op->o_tincr );
201 	rc = op->o_bd->be_bind( op, &rs );
202 	memset(pi->pwd.bv_val,0,pi->pwd.bv_len);
203 	/* quirk: on successful bind, caller has to send result. we need
204 	 * to make sure callbacks run.
205 	 */
206 	if (rc == LDAP_SUCCESS)
207 		send_ldap_result(op, &rs);
208 	switch(rs.sr_err) {
209 	case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break;
210 	case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break;
211 	default: rc = NSLCD_PAM_AUTH_ERR; break;
212 	}
213 finish:
214 	Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n",
215 		pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc );
216 	return rc;
217 }
218 
pam_authc(nssov_info * ni,TFILE * fp,Operation * op,uid_t calleruid)219 int pam_authc(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid)
220 {
221 	int32_t tmpint32;
222 	int rc;
223 	char uidc[32];
224 	char svcc[256];
225 	char ruserc[32];
226 	char rhostc[256];
227 	char ttyc[256];
228 	char pwdc[256];
229 	struct paminfo pi;
230 
231 
232 	READ_STRING(fp,uidc);
233 	pi.uid.bv_val = uidc;
234 	pi.uid.bv_len = tmpint32;
235 	READ_STRING(fp,svcc);
236 	pi.svc.bv_val = svcc;
237 	pi.svc.bv_len = tmpint32;
238 	READ_STRING(fp,ruserc);
239 	pi.ruser.bv_val = ruserc;
240 	pi.ruser.bv_len = tmpint32;
241 	READ_STRING(fp,rhostc);
242 	pi.rhost.bv_val = rhostc;
243 	pi.rhost.bv_len = tmpint32;
244 	READ_STRING(fp,ttyc);
245 	pi.tty.bv_val = ttyc;
246 	pi.tty.bv_len = tmpint32;
247 	READ_STRING(fp,pwdc);
248 	pi.pwd.bv_val = pwdc;
249 	pi.pwd.bv_len = tmpint32;
250 
251 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",
252 			pi.uid.bv_val ? pi.uid.bv_val : "NULL" );
253 
254 	BER_BVZERO(&pi.msg);
255 	pi.ispwdmgr = 0;
256 
257 	/* if service is "passwd" and "nssov-pam-password-prohibit-message */
258 	/* is set, deny the auth request */
259 	if (!strcmp(svcc, "passwd") &&
260 		!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
261 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n",
262 			"password_prohibit_message for passwd",
263 			ni->ni_pam_password_prohibit_message.bv_val );
264 		ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
265 		pi.authz = NSLCD_PAM_PERM_DENIED;
266 		rc = NSLCD_PAM_PERM_DENIED;
267 		goto finish;
268 	}
269 
270 	/* if username is null, pwdmgr password preliminary check */
271 	if (BER_BVISEMPTY(&pi.uid)) {
272 		if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
273 			/* pwdmgr dn not configured */
274 			Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
275 				"pwdmgr dn not configured" );
276 			ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg);
277 			pi.authz = NSLCD_PAM_PERM_DENIED;
278 			rc = NSLCD_PAM_PERM_DENIED;
279 			goto finish;
280 		} else if (calleruid != 0) {
281 			Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
282 				"caller is not root" );
283 			ber_str2bv("only root may do that", 0, 0, &pi.msg);
284 			pi.authz = NSLCD_PAM_PERM_DENIED;
285 			rc = NSLCD_PAM_PERM_DENIED;
286 			goto finish;
287 		} else {
288 			/* use pwdmgr dn */
289 			ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn);
290 		}
291 
292 		/* use pwdmgr pwd if configured */
293 		if (BER_BVISEMPTY(&pi.pwd)) {
294 			if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) {
295 				Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
296 					"no pwdmgr pwd" );
297 				ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg);
298 				pi.authz = NSLCD_PAM_PERM_DENIED;
299 				rc = NSLCD_PAM_PERM_DENIED;
300 				goto finish;
301 			}
302 			/* use configured pwdmgr pwd */
303 			memset((void *) pwdc, 0, 256);
304 			strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val,
305 					ni->ni_pam_pwdmgr_pwd.bv_len);
306 			pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len;
307 		}
308 		pi.ispwdmgr = 1;
309 	}
310 
311 
312 	rc = pam_do_bind(ni, fp, op, &pi);
313 
314 finish:
315 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n",
316 		pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc );
317 	WRITE_INT32(fp,NSLCD_VERSION);
318 	WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
319 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
320 	WRITE_INT32(fp,rc);
321 	WRITE_BERVAL(fp,&pi.uid);
322 	WRITE_INT32(fp,pi.authz);	/* authz */
323 	WRITE_BERVAL(fp,&pi.msg);	/* authzmsg */
324 	WRITE_INT32(fp,NSLCD_RESULT_END);
325 	return 0;
326 }
327 
328 static struct berval grpmsg =
329 	BER_BVC("Access denied by group check");
330 static struct berval hostmsg =
331 	BER_BVC("Access denied for this host");
332 static struct berval svcmsg =
333 	BER_BVC("Access denied for this service");
334 static struct berval uidmsg =
335 	BER_BVC("Access denied by UID check");
336 
pam_compare_cb(Operation * op,SlapReply * rs)337 static int pam_compare_cb(Operation *op, SlapReply *rs)
338 {
339 	if (rs->sr_err == LDAP_COMPARE_TRUE)
340 		op->o_callback->sc_private = (void *)1;
341 	return LDAP_SUCCESS;
342 }
343 
pam_authz(nssov_info * ni,TFILE * fp,Operation * op)344 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
345 {
346 	struct berval authzmsg = BER_BVNULL;
347 	int32_t tmpint32;
348 	char uidc[32];
349 	char svcc[256];
350 	char ruserc[32];
351 	char rhostc[256];
352 	char ttyc[256];
353 	int rc;
354 	struct paminfo pi;
355 	Entry *e = NULL;
356 	Attribute *a;
357 	slap_callback cb = {0};
358 
359 	READ_STRING(fp,uidc);
360 	pi.uid.bv_val = uidc;
361 	pi.uid.bv_len = tmpint32;
362 	READ_STRING(fp,svcc);
363 	pi.svc.bv_val = svcc;
364 	pi.svc.bv_len = tmpint32;
365 	READ_STRING(fp,ruserc);
366 	pi.ruser.bv_val = ruserc;
367 	pi.ruser.bv_len = tmpint32;
368 	READ_STRING(fp,rhostc);
369 	pi.rhost.bv_val = rhostc;
370 	pi.rhost.bv_len = tmpint32;
371 	READ_STRING(fp,ttyc);
372 	pi.tty.bv_val = ttyc;
373 	pi.tty.bv_len = tmpint32;
374 
375 	rc = pam_uid2dn(ni, op, &pi);
376 	if (rc) goto finish;
377 
378 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",
379 			pi.dn.bv_val ? pi.dn.bv_val : "NULL" );
380 
381 	/* See if they have access to the host and service */
382 	if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) {
383 		AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
384 		struct berval hostdn = BER_BVNULL;
385 		struct berval odn = op->o_ndn;
386 		SlapReply rs = {REP_RESULT};
387 		op->o_dn = pi.dn;
388 		op->o_ndn = pi.dn;
389 		{
390 			nssov_mapinfo *mi = &ni->ni_maps[NM_host];
391 			char fbuf[1024];
392 			struct berval filter = {sizeof(fbuf),fbuf};
393 			SlapReply rs2 = {REP_RESULT};
394 
395 			/* Lookup the host entry */
396 			nssov_filter_byname(mi,0,&global_host_bv,&filter);
397 			cb.sc_private = &hostdn;
398 			cb.sc_response = nssov_name2dn_cb;
399 			op->o_callback = &cb;
400 			op->o_req_dn = mi->mi_base;
401 			op->o_req_ndn = mi->mi_base;
402 			op->ors_scope = mi->mi_scope;
403 			op->ors_filterstr = filter;
404 			op->ors_filter = str2filter_x(op, filter.bv_val);
405 			op->ors_attrs = slap_anlist_no_attrs;
406 			op->ors_tlimit = SLAP_NO_LIMIT;
407 			op->ors_slimit = 2;
408 			rc = op->o_bd->be_search(op, &rs2);
409 			filter_free_x(op, op->ors_filter, 1);
410 
411 			if (BER_BVISEMPTY(&hostdn) &&
412 				!BER_BVISEMPTY(&ni->ni_pam_defhost)) {
413 				filter.bv_len = sizeof(fbuf);
414 				filter.bv_val = fbuf;
415 				rs_reinit(&rs2, REP_RESULT);
416 				nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter);
417 				op->ors_filterstr = filter;
418 				op->ors_filter = str2filter_x(op, filter.bv_val);
419 				rc = op->o_bd->be_search(op, &rs2);
420 				filter_free_x(op, op->ors_filter, 1);
421 			}
422 
423 			/* no host entry, no default host -> deny */
424 			if (BER_BVISEMPTY(&hostdn)) {
425 				rc = NSLCD_PAM_PERM_DENIED;
426 				authzmsg = hostmsg;
427 				goto finish;
428 			}
429 		}
430 
431 		cb.sc_response = pam_compare_cb;
432 		cb.sc_private = NULL;
433 		op->o_tag = LDAP_REQ_COMPARE;
434 		op->o_req_dn = hostdn;
435 		op->o_req_ndn = hostdn;
436 		ava.aa_desc = nssov_pam_svc_ad;
437 		ava.aa_value = pi.svc;
438 		op->orc_ava = &ava;
439 		rc = op->o_bd->be_compare( op, &rs );
440 		if ( cb.sc_private == NULL ) {
441 			authzmsg = svcmsg;
442 			rc = NSLCD_PAM_PERM_DENIED;
443 			goto finish;
444 		}
445 		op->o_dn = odn;
446 		op->o_ndn = odn;
447 	}
448 
449 	/* See if they're a member of the group */
450 	if ((ni->ni_pam_opts & NI_PAM_USERGRP) &&
451 		!BER_BVISEMPTY(&ni->ni_pam_group_dn) &&
452 		ni->ni_pam_group_ad) {
453 		AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
454 		SlapReply rs = {REP_RESULT};
455 		op->o_callback = &cb;
456 		cb.sc_response = pam_compare_cb;
457 		cb.sc_private = NULL;
458 		op->o_tag = LDAP_REQ_COMPARE;
459 		op->o_req_dn = ni->ni_pam_group_dn;
460 		op->o_req_ndn = ni->ni_pam_group_dn;
461 		ava.aa_desc = ni->ni_pam_group_ad;
462 		ava.aa_value = pi.dn;
463 		op->orc_ava = &ava;
464 		rc = op->o_bd->be_compare( op, &rs );
465 		if ( cb.sc_private == NULL ) {
466 			authzmsg = grpmsg;
467 			rc = NSLCD_PAM_PERM_DENIED;
468 			goto finish;
469 		}
470 	}
471 
472 	/* We need to check the user's entry for these bits */
473 	if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) ||
474 		ni->ni_pam_template_ad ||
475 		ni->ni_pam_min_uid || ni->ni_pam_max_uid ) {
476 		rc = be_entry_get_rw( op, &pi.dn, NULL, NULL, 0, &e );
477 		if (rc != LDAP_SUCCESS) {
478 			rc = NSLCD_PAM_USER_UNKNOWN;
479 			goto finish;
480 		}
481 	}
482 	if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) {
483 		a = attr_find(e->e_attrs, nssov_pam_host_ad);
484 		if (!a || attr_valfind( a,
485 			SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
486 			SLAP_MR_VALUE_OF_SYNTAX,
487 			&global_host_bv, NULL, op->o_tmpmemctx )) {
488 			rc = NSLCD_PAM_PERM_DENIED;
489 			authzmsg = hostmsg;
490 			goto finish;
491 		}
492 	}
493 	if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) {
494 		a = attr_find(e->e_attrs, nssov_pam_svc_ad);
495 		if (!a || attr_valfind( a,
496 			SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
497 			SLAP_MR_VALUE_OF_SYNTAX,
498 			&pi.svc, NULL, op->o_tmpmemctx )) {
499 			rc = NSLCD_PAM_PERM_DENIED;
500 			authzmsg = svcmsg;
501 			goto finish;
502 		}
503 	}
504 
505 /* from passwd.c */
506 #define UIDN_KEY	2
507 
508 	if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) {
509 		int id;
510 		char *tmp;
511 		nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
512 		a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc);
513 		if (!a) {
514 			rc = NSLCD_PAM_PERM_DENIED;
515 			authzmsg = uidmsg;
516 			goto finish;
517 		}
518 		id = (int)strtol(a->a_vals[0].bv_val,&tmp,0);
519 		if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') {
520 			rc = NSLCD_PAM_PERM_DENIED;
521 			authzmsg = uidmsg;
522 			goto finish;
523 		}
524 		if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) ||
525 			(ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) {
526 			rc = NSLCD_PAM_PERM_DENIED;
527 			authzmsg = uidmsg;
528 			goto finish;
529 		}
530 	}
531 
532 	if (ni->ni_pam_template_ad) {
533 		a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
534 		if (a)
535 			pi.uid = a->a_vals[0];
536 		else if (!BER_BVISEMPTY(&ni->ni_pam_template))
537 			pi.uid = ni->ni_pam_template;
538 	}
539 	rc = NSLCD_PAM_SUCCESS;
540 
541 finish:
542 	WRITE_INT32(fp,NSLCD_VERSION);
543 	WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
544 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
545 	WRITE_INT32(fp,rc);
546 	WRITE_BERVAL(fp,&authzmsg);
547 	WRITE_INT32(fp,NSLCD_RESULT_END);
548 	if (e) {
549 		be_entry_release_r(op, e);
550 	}
551 	switch (rc) {
552 	case NSLCD_PAM_SUCCESS:
553 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n" );
554 		break;
555 	case NSLCD_PAM_PERM_DENIED:
556 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n",
557 			authzmsg.bv_val ? authzmsg.bv_val : "NULL" );
558 		break;
559 	default:
560 		Debug(LDAP_DEBUG_TRACE,
561 			"nssov_pam_authz(): permission denied, rc (%d)\n",
562 			rc );
563 	}
564 	return 0;
565 }
566 
pam_sess(nssov_info * ni,TFILE * fp,Operation * op,int action)567 static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
568 {
569 	int32_t tmpint32;
570 	char svcc[256];
571 	char uidc[32];
572 	char ttyc[32];
573 	char rhostc[256];
574 	char ruserc[32];
575 	char sessionID[64];
576 	struct paminfo pi;
577 	slap_callback cb = {0};
578 	SlapReply rs = {REP_RESULT};
579 	char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
580 	struct berval timestamp, bv[2], *nbv;
581 	time_t stamp;
582 	Modifications mod;
583 	int rc = 0;
584 
585 	READ_STRING(fp,uidc);
586 	pi.uid.bv_val = uidc;
587 	pi.uid.bv_len = tmpint32;
588 	READ_STRING(fp,svcc);
589 	pi.svc.bv_val = svcc;
590 	pi.svc.bv_len = tmpint32;
591 	READ_STRING(fp,ruserc);
592 	pi.ruser.bv_val = ruserc;
593 	pi.ruser.bv_len = tmpint32;
594 	READ_STRING(fp,rhostc);
595 	pi.rhost.bv_val = rhostc;
596 	pi.rhost.bv_len = tmpint32;
597 	READ_STRING(fp,ttyc);
598 	pi.tty.bv_val = ttyc;
599 	pi.tty.bv_len = tmpint32;
600 
601 	if (action==NSLCD_ACTION_PAM_SESS_O) {
602 		slap_op_time( &op->o_time, &op->o_tincr );
603 		timestamp.bv_len = sizeof(timebuf);
604 		timestamp.bv_val = timebuf;
605 		stamp = op->o_time;
606 		slap_timestamp( &stamp, &timestamp );
607 	} else {
608 		READ_STRING(fp,sessionID);
609 		timestamp.bv_val = sessionID;
610 		timestamp.bv_len = tmpint32;
611 	}
612 
613 	rc = pam_uid2dn(ni, op, &pi);
614 	if (rc) goto done;
615 
616 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n",
617 		action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', pi.dn.bv_val );
618 
619 	if (!ni->ni_pam_sessions) {
620 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
621 			action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
622 			"pam session(s) not configured, ignored" );
623 		rc = -1;
624 		goto done;
625 	}
626 
627 	{
628 		int i, found=0;
629 		for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) {
630 			if (ni->ni_pam_sessions[i].bv_len != pi.svc.bv_len)
631 				continue;
632 			if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, pi.svc.bv_val)) {
633 				found = 1;
634 				break;
635 			}
636 		}
637 		if (!found) {
638 			Debug(LDAP_DEBUG_TRACE,
639 				"nssov_pam_sess_%c(): service(%s) not configured, ignored\n",
640 				action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
641 				pi.svc.bv_val );
642 			rc = -1;
643 			goto done;
644 		}
645 	}
646 
647 	bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + pi.svc.bv_len +
648 		pi.tty.bv_len + pi.ruser.bv_len + pi.rhost.bv_len + STRLENOF("    (@)");
649 	bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx );
650 	sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)",
651 		timestamp.bv_val, global_host_bv.bv_val, pi.svc.bv_val, pi.tty.bv_val,
652 		pi.ruser.bv_val, pi.rhost.bv_val);
653 
654 	Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n",
655 			action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val );
656 
657 	mod.sml_numvals = 1;
658 	mod.sml_values = bv;
659 	BER_BVZERO(&bv[1]);
660 	attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx );
661 	mod.sml_nvalues = nbv;
662 	mod.sml_desc = ad_loginStatus;
663 	mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD :
664 		LDAP_MOD_DELETE;
665 	mod.sml_flags = SLAP_MOD_INTERNAL;
666 	mod.sml_next = NULL;
667 
668 	cb.sc_response = slap_null_cb;
669 	op->o_callback = &cb;
670 	op->o_tag = LDAP_REQ_MODIFY;
671 	op->o_dn = op->o_bd->be_rootdn;
672 	op->o_ndn = op->o_bd->be_rootndn;
673 	op->orm_modlist = &mod;
674 	op->orm_no_opattrs = 1;
675 	op->o_req_dn = pi.dn;
676 	op->o_req_ndn = pi.dn;
677 	if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) {
678 		Debug(LDAP_DEBUG_TRACE,
679 			"nssov_pam_sess_%c(): modify op failed\n",
680 			action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c' );
681 		rc = -1;
682 	}
683 
684 	if ( mod.sml_next ) {
685 		slap_mods_free( mod.sml_next, 1 );
686 	}
687 	ber_bvarray_free_x( nbv, op->o_tmpmemctx );
688 
689 done:;
690 
691 	if (rc == 0) {
692 		Debug(LDAP_DEBUG_TRACE,
693 			"nssov_pam_sess_%c(): success\n",
694 			action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c' );
695 	}
696 	WRITE_INT32(fp,NSLCD_VERSION);
697 	WRITE_INT32(fp,action);
698 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
699 	if (action==NSLCD_ACTION_PAM_SESS_O)
700 		WRITE_STRING(fp,timestamp.bv_val);
701 	WRITE_INT32(fp,NSLCD_RESULT_END);
702 	return 0;
703 }
704 
pam_sess_o(nssov_info * ni,TFILE * fp,Operation * op)705 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
706 {
707 	return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O);
708 }
709 
pam_sess_c(nssov_info * ni,TFILE * fp,Operation * op)710 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
711 {
712 	return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C);
713 }
714 
pam_pwmod(nssov_info * ni,TFILE * fp,Operation * op,uid_t calleruid)715 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid)
716 {
717 	struct berval npw;
718 	int32_t tmpint32;
719 	char uidc[32];
720 	char svcc[256];
721 	char ruserc[32];
722 	char rhostc[256];
723 	char ttyc[256];
724 	int asroot;
725 	char opwc[256];
726 	char npwc[256];
727 	struct paminfo pi;
728 	int rc;
729 
730 	READ_STRING(fp,uidc);
731 	pi.uid.bv_val = uidc;
732 	pi.uid.bv_len = tmpint32;
733 	READ_STRING(fp,svcc);
734 	pi.svc.bv_val = svcc;
735 	pi.svc.bv_len = tmpint32;
736 	READ_STRING(fp,ruserc);
737 	pi.ruser.bv_val = svcc;
738 	pi.ruser.bv_len = tmpint32;
739 	READ_STRING(fp,rhostc);
740 	pi.rhost.bv_val = svcc;
741 	pi.rhost.bv_len = tmpint32;
742 	READ_STRING(fp,ttyc);
743 	pi.tty.bv_val = svcc;
744 	pi.tty.bv_len = tmpint32;
745 	READ_INT32(fp, asroot);
746 	READ_STRING(fp,opwc);
747 	pi.pwd.bv_val = opwc;
748 	pi.pwd.bv_len = tmpint32;
749 	READ_STRING(fp,npwc);
750 	npw.bv_val = npwc;
751 	npw.bv_len = tmpint32;
752 
753 	rc = pam_uid2dn(ni, op, &pi);
754 	if (rc) goto done;
755 
756 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s %s\n",
757 		pi.dn.bv_val ? pi.dn.bv_val : "NULL",
758 		pi.uid.bv_val ? pi.uid.bv_val : "NULL",
759 		asroot ? "as root" : "as user");
760 
761 	BER_BVZERO(&pi.msg);
762 	pi.ispwdmgr = 0;
763 
764 	/* nssov_pam prohibits password mod */
765 	if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
766 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s (%s)\n",
767 			"password_prohibit_message",
768 			ni->ni_pam_password_prohibit_message.bv_val );
769 		ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
770 		rc = NSLCD_PAM_PERM_DENIED;
771 		goto done;
772 	}
773 
774 	if (asroot) {
775 		if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
776 			Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
777 				"pwdmgr not configured" );
778 			ber_str2bv("pwdmgr not configured", 0, 0, &pi.msg);
779 			rc = NSLCD_PAM_PERM_DENIED;
780 			goto done;
781 		}
782 		if (calleruid != 0) {
783 			Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s\n",
784 				"caller is not root" );
785 			ber_str2bv("only root may do that", 0, 0, &pi.msg);
786 			rc = NSLCD_PAM_PERM_DENIED;
787 			goto done;
788 		}
789 		/* root user requesting pwmod */
790 		pi.ispwdmgr = 1;
791 	}
792 
793 	if (!pi.ispwdmgr && BER_BVISEMPTY(&pi.pwd)) {
794 		Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
795 			"not pwdmgr and old pwd empty" );
796 		ber_str2bv("must provide old password", 0, 0, &pi.msg);
797 		rc = NSLCD_PAM_PERM_DENIED;
798 		goto done;
799 	}
800 
801 	BerElementBuffer berbuf;
802 	BerElement *ber = (BerElement *)&berbuf;
803 	struct berval bv;
804 	SlapReply rs = {REP_RESULT};
805 	slap_callback cb = {0};
806 
807 	ber_init_w_nullc(ber, LBER_USE_DER);
808 	ber_printf(ber, "{");
809 	if (!BER_BVISEMPTY(&pi.dn))
810 		ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
811 			&pi.dn);
812 	/* supply old pwd whenever it's given */
813 	if (!BER_BVISEMPTY(&pi.pwd))
814 		ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD,
815 			&pi.pwd);
816 	if (!BER_BVISEMPTY(&npw))
817 		ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
818 			&npw);
819 	ber_printf(ber, "N}");
820 	ber_flatten2(ber, &bv, 0);
821 	op->o_tag = LDAP_REQ_EXTENDED;
822 	op->ore_reqoid = slap_EXOP_MODIFY_PASSWD;
823 	op->ore_reqdata = &bv;
824 
825 	if (pi.ispwdmgr) {
826 		/* root user changing end-user passwords */
827 		op->o_dn = ni->ni_pam_pwdmgr_dn;
828 		op->o_ndn = ni->ni_pam_pwdmgr_dn;
829 	} else {
830 		/* end-user self-pwd-mod */
831 		op->o_dn = pi.dn;
832 		op->o_ndn = pi.dn;
833 	}
834 	op->o_callback = &cb;
835 	op->o_conn->c_authz_backend = op->o_bd;
836 	cb.sc_response = slap_null_cb;
837 	op->o_bd = frontendDB;
838 	rc = op->o_bd->be_extended(op, &rs);
839 	if (rs.sr_text)
840 		ber_str2bv(rs.sr_text, 0, 0, &pi.msg);
841 	if (rc == LDAP_SUCCESS)
842 		rc = NSLCD_PAM_SUCCESS;
843 	else
844 		rc = NSLCD_PAM_PERM_DENIED;
845 
846 done:;
847 	Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), rc (%d)\n", rc );
848 	WRITE_INT32(fp,NSLCD_VERSION);
849 	WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
850 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
851 	WRITE_INT32(fp,rc);
852 	WRITE_BERVAL(fp,&pi.msg);
853 	return 0;
854 }
855 
nssov_pam_init()856 int nssov_pam_init()
857 {
858 	int code = 0;
859 	const char *text;
860 	if (!ad_loginStatus)
861 		code = slap_str2ad("loginStatus", &ad_loginStatus, &text);
862 
863 	return code;
864 }
865