openldap/contrib/slapd-modules/nssov/pam.c

585 lines
15 KiB
C
Raw Normal View History

2009-04-17 20:11:33 +08:00
/* pam.c - pam processing routines */
/* $OpenLDAP$ */
/*
* Copyright 2009 by Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "nssov.h"
#include <security/pam_modules.h>
static int ppolicy_cid;
2009-04-20 18:25:24 +08:00
struct paminfo {
struct berval uid;
struct berval dn;
struct berval svc;
struct berval pwd;
int authz;
struct berval msg;
};
static int pam_bindcb(
2009-04-17 20:11:33 +08:00
Operation *op, SlapReply *rs)
{
2009-04-20 18:25:24 +08:00
struct paminfo *pi = op->o_callback->sc_private;
LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
rs->sr_ctrls, NULL);
if (ctrl) {
LDAP *ld;
ber_int_t expire, grace;
LDAPPasswordPolicyError error;
ldap_create(&ld);
if (ld) {
int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
&expire,&grace,&error);
if (rc == LDAP_SUCCESS) {
if (expire >= 0) {
char *unit = "seconds";
if (expire > 60) {
expire /= 60;
unit = "minutes";
}
if (expire > 60) {
expire /= 60;
unit = "hours";
}
if (expire > 24) {
expire /= 24;
unit = "days";
}
#if 0 /* Who warns about expiration so far in advance? */
if (expire > 7) {
expire /= 7;
unit = "weeks";
}
if (expire > 4) {
expire /= 4;
unit = "months";
}
if (expire > 12) {
expire /= 12;
unit = "years";
}
#endif
2009-04-20 18:25:24 +08:00
pi->msg.bv_len = sprintf(pi->msg.bv_val,
"\nWARNING: Password expires in %d %s\n", expire, unit);
} else if (grace > 0) {
2009-04-20 18:25:24 +08:00
pi->msg.bv_len = sprintf(pi->msg.bv_val,
"Password expired; %d grace logins remaining",
grace);
2009-04-20 18:25:24 +08:00
pi->authz = PAM_NEW_AUTHTOK_REQD;
} else if (error != PP_noError) {
ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
2009-04-20 18:25:24 +08:00
&pi->msg);
switch (error) {
case PP_passwordExpired:
/* report this during authz */
rs->sr_err = LDAP_SUCCESS;
/* fallthru */
case PP_changeAfterReset:
2009-04-20 18:25:24 +08:00
pi->authz = PAM_NEW_AUTHTOK_REQD;
}
}
}
ldap_ld_free(ld,0,NULL,NULL);
}
}
2009-04-17 20:11:33 +08:00
return LDAP_SUCCESS;
}
2009-04-20 18:25:24 +08:00
int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
struct paminfo *pi)
2009-04-17 20:11:33 +08:00
{
int rc;
slap_callback cb = {0};
SlapReply rs = {REP_RESULT};
2009-04-20 18:25:24 +08:00
struct berval sdn;
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
pi->msg.bv_val = pi->pwd.bv_val;
pi->msg.bv_len = 0;
pi->authz = PAM_SUCCESS;
BER_BVZERO(&pi->dn);
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
if (!isvalidusername(&pi->uid)) {
Debug(LDAP_DEBUG_ANY,"nssov_pam_do_bind(%s): invalid user name\n",
pi->uid.bv_val,0,0);
2009-04-17 20:11:33 +08:00
rc = PAM_USER_UNKNOWN;
goto finish;
}
if (ni->ni_pam_opts & NI_PAM_SASL2DN) {
int hlen = global_host_bv.bv_len;
/* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
2009-04-20 18:25:24 +08:00
sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen +
STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth",
2009-04-20 18:25:24 +08:00
pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val);
slap_sasl2dn(op, &sdn, &pi->dn, 0);
op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
}
2009-04-17 20:11:33 +08:00
/* If no luck, do a basic uid search */
2009-04-20 18:25:24 +08:00
if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
nssov_uid2dn(op, ni, &pi->uid, &pi->dn);
if (!BER_BVISEMPTY(&pi->dn)) {
sdn = pi->dn;
dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx );
2009-04-17 20:11:33 +08:00
}
}
BER_BVZERO(&sdn);
2009-04-20 18:25:24 +08:00
if (BER_BVISEMPTY(&pi->dn)) {
rc = PAM_USER_UNKNOWN;
goto finish;
}
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
if (BER_BVISEMPTY(&pi->pwd)) {
rc = PAM_IGNORE;
goto finish;
}
/* Should only need to do this once at open time, but there's always
* the possibility that ppolicy will get loaded later.
*/
if (!ppolicy_cid) {
rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
&ppolicy_cid);
}
/* of course, 0 is a valid cid, but it won't be ppolicy... */
if (ppolicy_cid) {
op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
}
cb.sc_response = pam_bindcb;
2009-04-20 18:25:24 +08:00
cb.sc_private = pi;
2009-04-17 20:11:33 +08:00
op->o_callback = &cb;
op->o_dn.bv_val[0] = 0;
op->o_dn.bv_len = 0;
op->o_ndn.bv_val[0] = 0;
op->o_ndn.bv_len = 0;
op->o_tag = LDAP_REQ_BIND;
op->o_protocol = LDAP_VERSION3;
op->orb_method = LDAP_AUTH_SIMPLE;
2009-04-20 18:25:24 +08:00
op->orb_cred = pi->pwd;
op->o_req_dn = pi->dn;
op->o_req_ndn = pi->dn;
2009-04-17 20:11:33 +08:00
slap_op_time( &op->o_time, &op->o_tincr );
rc = op->o_bd->be_bind( op, &rs );
2009-04-20 18:25:24 +08:00
memset(pi->pwd.bv_val,0,pi->pwd.bv_len);
/* quirk: on successful bind, caller has to send result. we need
* to make sure callbacks run.
*/
if (rc == LDAP_SUCCESS)
send_ldap_result(op, &rs);
2009-04-17 20:11:33 +08:00
switch(rs.sr_err) {
case LDAP_SUCCESS: rc = PAM_SUCCESS; break;
case LDAP_INVALID_CREDENTIALS: rc = PAM_AUTH_ERR; break;
default: rc = PAM_AUTH_ERR; break;
}
2009-04-20 18:25:24 +08:00
finish:
return rc;
}
int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
{
int32_t tmpint32;
int rc;
slap_callback cb = {0};
SlapReply rs = {REP_RESULT};
char dnc[1024];
char uidc[32];
char svcc[256];
char pwdc[256];
struct berval sdn, dn;
struct paminfo pi;
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
pi.uid.bv_val = uidc;
pi.uid.bv_len = tmpint32;
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
pi.dn.bv_val = dnc;
pi.dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
pi.svc.bv_val = svcc;
pi.svc.bv_len = tmpint32;
READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
pi.pwd.bv_val = pwdc;
pi.pwd.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",pi.uid.bv_val,0,0);
rc = pam_do_bind(ni, fp, op, &pi);
2009-04-17 20:11:33 +08:00
finish:
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
2009-04-20 18:25:24 +08:00
WRITE_BERVAL(fp,&pi.uid);
WRITE_BERVAL(fp,&pi.dn);
2009-04-17 20:11:33 +08:00
WRITE_INT32(fp,rc);
2009-04-20 18:25:24 +08:00
WRITE_INT32(fp,pi.authz); /* authz */
WRITE_BERVAL(fp,&pi.msg); /* authzmsg */
2009-04-17 20:11:33 +08:00
return 0;
}
static int pam_nullcb(Operation *op, SlapReply *rs)
{
return LDAP_SUCCESS;
}
static struct berval grpmsg =
BER_BVC("Access denied by group check");
static struct berval hostmsg =
BER_BVC("Access denied for this host");
static struct berval svcmsg =
BER_BVC("Access denied for this service");
2009-04-20 11:53:09 +08:00
static struct berval uidmsg =
BER_BVC("Access denied by UID check");
2009-04-17 20:11:33 +08:00
int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
{
2009-04-20 18:25:24 +08:00
struct berval dn, uid, svc;
2009-04-17 20:11:33 +08:00
struct berval authzmsg = BER_BVNULL;
int32_t tmpint32;
char dnc[1024];
2009-04-20 18:25:24 +08:00
char uidc[32];
2009-04-17 20:11:33 +08:00
char svcc[256];
int rc = PAM_SUCCESS;
Entry *e = NULL;
Attribute *a;
SlapReply rs = {REP_RESULT};
slap_callback cb = {0};
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
uid.bv_val = uidc;
uid.bv_len = tmpint32;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0);
/* We don't do authorization if they weren't authenticated by us */
if (BER_BVISEMPTY(&dn)) {
rc = PAM_USER_UNKNOWN;
goto finish;
}
/* See if they have access to the host and service */
2009-04-20 11:18:34 +08:00
if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) {
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
struct berval hostdn = BER_BVNULL;
2009-04-20 11:18:34 +08:00
struct berval odn = op->o_ndn;
op->o_dn = dn;
op->o_ndn = dn;
{
nssov_mapinfo *mi = &ni->ni_maps[NM_host];
char fbuf[1024];
struct berval filter = {sizeof(fbuf),fbuf};
SlapReply rs2 = {REP_RESULT};
/* Lookup the host entry */
nssov_filter_byname(mi,0,&global_host_bv,&filter);
cb.sc_private = &hostdn;
cb.sc_response = nssov_name2dn_cb;
op->o_callback = &cb;
op->o_req_dn = mi->mi_base;
op->o_req_ndn = mi->mi_base;
op->ors_scope = mi->mi_scope;
op->ors_filterstr = filter;
op->ors_filter = str2filter_x(op, filter.bv_val);
op->ors_attrs = slap_anlist_no_attrs;
op->ors_tlimit = SLAP_NO_LIMIT;
op->ors_slimit = 2;
rc = op->o_bd->be_search(op, &rs2);
filter_free_x(op, op->ors_filter, 1);
if (BER_BVISEMPTY(&hostdn) &&
!BER_BVISEMPTY(&ni->ni_pam_defhost)) {
filter.bv_len = sizeof(fbuf);
filter.bv_val = fbuf;
memset(&rs2, 0, sizeof(rs2));
rs2.sr_type = REP_RESULT;
nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter);
op->ors_filterstr = filter;
op->ors_filter = str2filter_x(op, filter.bv_val);
rc = op->o_bd->be_search(op, &rs2);
filter_free_x(op, op->ors_filter, 1);
}
/* no host entry, no default host -> deny */
if (BER_BVISEMPTY(&hostdn)) {
rc = PAM_PERM_DENIED;
authzmsg = hostmsg;
goto finish;
}
}
cb.sc_response = pam_nullcb;
cb.sc_private = NULL;
op->o_tag = LDAP_REQ_COMPARE;
op->o_req_dn = hostdn;
op->o_req_ndn = hostdn;
2009-04-20 11:18:34 +08:00
ava.aa_desc = nssov_pam_svc_ad;
ava.aa_value = svc;
op->orc_ava = &ava;
rc = op->o_bd->be_compare( op, &rs );
if ( rs.sr_err != LDAP_COMPARE_TRUE ) {
authzmsg = svcmsg;
rc = PAM_PERM_DENIED;
goto finish;
}
2009-04-20 11:18:34 +08:00
op->o_dn = odn;
op->o_ndn = odn;
}
/* See if they're a member of the group */
if ((ni->ni_pam_opts & NI_PAM_USERGRP) &&
!BER_BVISEMPTY(&ni->ni_pam_group_dn) &&
ni->ni_pam_group_ad) {
AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
op->o_callback = &cb;
cb.sc_response = pam_nullcb;
op->o_tag = LDAP_REQ_COMPARE;
op->o_req_dn = ni->ni_pam_group_dn;
op->o_req_ndn = ni->ni_pam_group_dn;
ava.aa_desc = ni->ni_pam_group_ad;
ava.aa_value = dn;
op->orc_ava = &ava;
rc = op->o_bd->be_compare( op, &rs );
if ( rs.sr_err != LDAP_COMPARE_TRUE ) {
authzmsg = grpmsg;
rc = PAM_PERM_DENIED;
goto finish;
}
}
/* We need to check the user's entry for these bits */
if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) ||
2009-04-20 11:53:09 +08:00
ni->ni_pam_template_ad ||
ni->ni_pam_min_uid || ni->ni_pam_max_uid ) {
rc = be_entry_get_rw( op, &dn, NULL, NULL, 0, &e );
if (rc != LDAP_SUCCESS) {
rc = PAM_USER_UNKNOWN;
goto finish;
}
}
2009-04-20 11:18:34 +08:00
if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) {
a = attr_find(e->e_attrs, nssov_pam_host_ad);
if (!a || value_find_ex( nssov_pam_host_ad,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
a->a_vals, &global_host_bv, op->o_tmpmemctx )) {
rc = PAM_PERM_DENIED;
authzmsg = hostmsg;
goto finish;
}
}
2009-04-20 11:18:34 +08:00
if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) {
a = attr_find(e->e_attrs, nssov_pam_svc_ad);
if (!a || value_find_ex( nssov_pam_svc_ad,
SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
a->a_vals, &svc, op->o_tmpmemctx )) {
rc = PAM_PERM_DENIED;
authzmsg = svcmsg;
goto finish;
}
}
2009-04-20 11:53:09 +08:00
/* from passwd.c */
#define UIDN_KEY 2
if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) {
int id;
char *tmp;
nssov_mapinfo *mi = &ni->ni_maps[NM_host];
a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc);
if (!a) {
rc = PAM_PERM_DENIED;
authzmsg = uidmsg;
goto finish;
}
id = (int)strtol(a->a_vals[0].bv_val,&tmp,0);
if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') {
rc = PAM_PERM_DENIED;
authzmsg = uidmsg;
goto finish;
}
if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) ||
(ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) {
rc = PAM_PERM_DENIED;
authzmsg = uidmsg;
goto finish;
}
}
if (ni->ni_pam_template_ad) {
a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
if (a)
2009-04-20 18:25:24 +08:00
uid = a->a_vals[0];
else if (!BER_BVISEMPTY(&ni->ni_pam_template))
2009-04-20 18:25:24 +08:00
uid = ni->ni_pam_template;
}
finish:
2009-04-17 20:11:33 +08:00
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
2009-04-20 18:25:24 +08:00
WRITE_BERVAL(fp,&uid);
WRITE_BERVAL(fp,&dn);
WRITE_INT32(fp,rc);
2009-04-17 20:11:33 +08:00
WRITE_BERVAL(fp,&authzmsg);
if (e) {
be_entry_release_r(op, e);
}
2009-04-17 20:11:33 +08:00
return 0;
}
int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
{
2009-04-20 18:25:24 +08:00
struct berval dn, uid, svc;
2009-04-17 20:11:33 +08:00
int32_t tmpint32;
char dnc[1024];
char svcc[256];
2009-04-20 18:25:24 +08:00
char uidc[32];
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
uid.bv_val = uidc;
uid.bv_len = tmpint32;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_o(%s)\n",dn.bv_val,0,0);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
return 0;
}
int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
{
2009-04-20 18:25:24 +08:00
struct berval dn, uid, svc;
2009-04-17 20:11:33 +08:00
int32_t tmpint32;
char dnc[1024];
char svcc[256];
2009-04-20 18:25:24 +08:00
char uidc[32];
2009-04-17 20:11:33 +08:00
2009-04-20 18:25:24 +08:00
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
uid.bv_val = uidc;
uid.bv_len = tmpint32;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
dn.bv_val = dnc;
dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
svc.bv_val = svcc;
svc.bv_len = tmpint32;
Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_c(%s)\n",dn.bv_val,0,0);
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
return 0;
}
int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
{
2009-04-20 18:25:24 +08:00
struct berval npw;
2009-04-17 20:11:33 +08:00
int32_t tmpint32;
char dnc[1024];
2009-04-20 18:25:24 +08:00
char uidc[32];
2009-04-17 20:11:33 +08:00
char opwc[256];
char npwc[256];
2009-04-20 18:25:24 +08:00
char svcc[256];
struct paminfo pi;
int rc;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,uidc,sizeof(uidc));
2009-04-20 18:25:24 +08:00
pi.uid.bv_val = uidc;
pi.uid.bv_len = tmpint32;
READ_STRING_BUF2(fp,dnc,sizeof(dnc));
pi.dn.bv_val = dnc;
pi.dn.bv_len = tmpint32;
READ_STRING_BUF2(fp,svcc,sizeof(svcc));
pi.svc.bv_val = svcc;
pi.svc.bv_len = tmpint32;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,opwc,sizeof(opwc));
2009-04-20 18:25:24 +08:00
pi.pwd.bv_val = opwc;
pi.pwd.bv_len = tmpint32;
2009-04-17 20:11:33 +08:00
READ_STRING_BUF2(fp,npwc,sizeof(npwc));
npw.bv_val = npwc;
npw.bv_len = tmpint32;
2009-04-20 18:25:24 +08:00
Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",
pi.dn.bv_val,pi.uid.bv_val,0);
BER_BVZERO(&pi.msg);
/* This is a prelim check */
if (BER_BVISEMPTY(&pi.dn)) {
rc = pam_do_bind(ni,fp,op,&pi);
if (rc == PAM_IGNORE)
rc = PAM_SUCCESS;
} else {
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
struct berval bv;
SlapReply rs = {REP_RESULT};
slap_callback cb = {0};
ber_init_w_nullc(ber, LBER_USE_DER);
ber_printf(ber, "{");
if (!BER_BVISEMPTY(&pi.pwd))
ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD,
&pi.pwd);
if (!BER_BVISEMPTY(&npw))
ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
&npw);
ber_printf(ber, "N}");
ber_flatten2(ber, &bv, 0);
op->o_tag = LDAP_REQ_EXTENDED;
op->ore_reqoid = slap_EXOP_MODIFY_PASSWD;
op->ore_reqdata = &bv;
op->o_dn = pi.dn;
op->o_ndn = pi.dn;
op->o_callback = &cb;
op->o_conn->c_authz_backend = op->o_bd;
cb.sc_response = pam_nullcb;
op->o_bd = frontendDB;
rc = op->o_bd->be_extended(op, &rs);
if (rs.sr_text)
ber_str2bv(rs.sr_text, 0, 0, &pi.msg);
if (rc == LDAP_SUCCESS)
rc = PAM_SUCCESS;
else
rc = PAM_PERM_DENIED;
}
2009-04-17 20:11:33 +08:00
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
2009-04-20 18:25:24 +08:00
WRITE_BERVAL(fp,&pi.uid);
WRITE_BERVAL(fp,&pi.dn);
WRITE_INT32(fp,rc);
WRITE_BERVAL(fp,&pi.msg);
2009-04-17 20:11:33 +08:00
return 0;
}