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
27static int ppolicy_cid;
28static AttributeDescription *ad_loginStatus;
29
30struct 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
43static 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
113static 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
153int 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	}
213finish:
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
219int 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
314finish:
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
328static struct berval grpmsg =
329	BER_BVC("Access denied by group check");
330static struct berval hostmsg =
331	BER_BVC("Access denied for this host");
332static struct berval svcmsg =
333	BER_BVC("Access denied for this service");
334static struct berval uidmsg =
335	BER_BVC("Access denied by UID check");
336
337static 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
344int 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
541finish:
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
567static 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
689done:;
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
705int 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
710int 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
715int 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
846done:;
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
856int 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