/* $NetBSD: pam.c,v 1.3 2021/08/14 16:14:52 christos Exp $ */ /* pam.c - pam processing routines */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2008-2021 The OpenLDAP Foundation. * Portions Copyright 2008 by Howard Chu, Symas Corp. * Portions Copyright 2013 by Ted C. Cheng, 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 * . */ #include "nssov.h" #include "lutil.h" #undef ldap_debug /* silence a warning in ldap-int.h */ #include "../../../libraries/libldap/ldap-int.h" /* for ldap_ld_free */ static int ppolicy_cid; static AttributeDescription *ad_loginStatus; struct paminfo { struct berval uid; struct berval dn; struct berval svc; struct berval ruser; struct berval rhost; struct berval tty; struct berval pwd; int authz; struct berval msg; int ispwdmgr; }; static int pam_bindcb( Operation *op, SlapReply *rs) { 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 pi->msg.bv_len = sprintf(pi->msg.bv_val, "\nWARNING: Password expires in %d %s\n", expire, unit); } else if (grace > 0) { pi->msg.bv_len = sprintf(pi->msg.bv_val, "Password expired; %d grace logins remaining", grace); pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; } else if (error != PP_noError) { ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0, &pi->msg); switch (error) { case PP_passwordExpired: /* report this during authz */ rs->sr_err = LDAP_SUCCESS; /* fallthru */ case PP_changeAfterReset: pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; } } } ldap_ld_free(ld,0,NULL,NULL); } } return LDAP_SUCCESS; } static int pam_uid2dn(nssov_info *ni, Operation *op, struct paminfo *pi) { struct berval sdn; BER_BVZERO(&pi->dn); if (!isvalidusername(&pi->uid)) { Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n", pi->uid.bv_val ? pi->uid.bv_val : "NULL" ); return NSLCD_PAM_USER_UNKNOWN; } if (ni->ni_pam_opts & NI_PAM_SASL2DN) { int hlen = global_host_bv.bv_len; /* cn=+uid=,cn=,cn=pam,cn=auth */ 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", 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 ); } /* If no luck, do a basic uid search */ 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 ); } } if (BER_BVISEMPTY(&pi->dn)) { return NSLCD_PAM_USER_UNKNOWN; } return 0; } int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op, struct paminfo *pi) { int rc; slap_callback cb = {0}; SlapReply rs = {REP_RESULT}; pi->msg.bv_val = pi->pwd.bv_val; pi->msg.bv_len = 0; pi->authz = NSLCD_PAM_SUCCESS; if (!pi->ispwdmgr) { rc = pam_uid2dn(ni, op, pi); if (rc) goto finish; if (BER_BVISEMPTY(&pi->pwd)) { rc = NSLCD_PAM_PERM_DENIED; 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; cb.sc_private = pi; 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; op->orb_cred = pi->pwd; op->o_req_dn = pi->dn; op->o_req_ndn = pi->dn; slap_op_time( &op->o_time, &op->o_tincr ); rc = op->o_bd->be_bind( op, &rs ); 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); switch(rs.sr_err) { case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break; case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break; default: rc = NSLCD_PAM_AUTH_ERR; break; } finish: Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n", pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc ); return rc; } int pam_authc(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid) { int32_t tmpint32; int rc; char uidc[32]; char svcc[256]; char ruserc[32]; char rhostc[256]; char ttyc[256]; char pwdc[256]; struct paminfo pi; READ_STRING(fp,uidc); pi.uid.bv_val = uidc; pi.uid.bv_len = tmpint32; READ_STRING(fp,svcc); pi.svc.bv_val = svcc; pi.svc.bv_len = tmpint32; READ_STRING(fp,ruserc); pi.ruser.bv_val = ruserc; pi.ruser.bv_len = tmpint32; READ_STRING(fp,rhostc); pi.rhost.bv_val = rhostc; pi.rhost.bv_len = tmpint32; READ_STRING(fp,ttyc); pi.tty.bv_val = ttyc; pi.tty.bv_len = tmpint32; READ_STRING(fp,pwdc); pi.pwd.bv_val = pwdc; pi.pwd.bv_len = tmpint32; Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n", pi.uid.bv_val ? pi.uid.bv_val : "NULL" ); BER_BVZERO(&pi.msg); pi.ispwdmgr = 0; /* if service is "passwd" and "nssov-pam-password-prohibit-message */ /* is set, deny the auth request */ if (!strcmp(svcc, "passwd") && !BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n", "password_prohibit_message for passwd", ni->ni_pam_password_prohibit_message.bv_val ); ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg); pi.authz = NSLCD_PAM_PERM_DENIED; rc = NSLCD_PAM_PERM_DENIED; goto finish; } /* if username is null, pwdmgr password preliminary check */ if (BER_BVISEMPTY(&pi.uid)) { if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) { /* pwdmgr dn not configured */ Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", "pwdmgr dn not configured" ); ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg); pi.authz = NSLCD_PAM_PERM_DENIED; rc = NSLCD_PAM_PERM_DENIED; goto finish; } else if (calleruid != 0) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", "caller is not root" ); ber_str2bv("only root may do that", 0, 0, &pi.msg); pi.authz = NSLCD_PAM_PERM_DENIED; rc = NSLCD_PAM_PERM_DENIED; goto finish; } else { /* use pwdmgr dn */ ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn); } /* use pwdmgr pwd if configured */ if (BER_BVISEMPTY(&pi.pwd)) { if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n", "no pwdmgr pwd" ); ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg); pi.authz = NSLCD_PAM_PERM_DENIED; rc = NSLCD_PAM_PERM_DENIED; goto finish; } /* use configured pwdmgr pwd */ memset((void *) pwdc, 0, 256); strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_len); pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len; } pi.ispwdmgr = 1; } rc = pam_do_bind(ni, fp, op, &pi); finish: Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n", pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc ); WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC); WRITE_INT32(fp,NSLCD_RESULT_BEGIN); WRITE_INT32(fp,rc); WRITE_BERVAL(fp,&pi.uid); WRITE_INT32(fp,pi.authz); /* authz */ WRITE_BERVAL(fp,&pi.msg); /* authzmsg */ WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } 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"); static struct berval uidmsg = BER_BVC("Access denied by UID check"); static int pam_compare_cb(Operation *op, SlapReply *rs) { if (rs->sr_err == LDAP_COMPARE_TRUE) op->o_callback->sc_private = (void *)1; return LDAP_SUCCESS; } int pam_authz(nssov_info *ni,TFILE *fp,Operation *op) { struct berval authzmsg = BER_BVNULL; int32_t tmpint32; char uidc[32]; char svcc[256]; char ruserc[32]; char rhostc[256]; char ttyc[256]; int rc; struct paminfo pi; Entry *e = NULL; Attribute *a; slap_callback cb = {0}; READ_STRING(fp,uidc); pi.uid.bv_val = uidc; pi.uid.bv_len = tmpint32; READ_STRING(fp,svcc); pi.svc.bv_val = svcc; pi.svc.bv_len = tmpint32; READ_STRING(fp,ruserc); pi.ruser.bv_val = ruserc; pi.ruser.bv_len = tmpint32; READ_STRING(fp,rhostc); pi.rhost.bv_val = rhostc; pi.rhost.bv_len = tmpint32; READ_STRING(fp,ttyc); pi.tty.bv_val = ttyc; pi.tty.bv_len = tmpint32; rc = pam_uid2dn(ni, op, &pi); if (rc) goto finish; Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n", pi.dn.bv_val ? pi.dn.bv_val : "NULL" ); /* See if they have access to the host and service */ if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) { AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; struct berval hostdn = BER_BVNULL; struct berval odn = op->o_ndn; SlapReply rs = {REP_RESULT}; op->o_dn = pi.dn; op->o_ndn = pi.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; rs_reinit(&rs2, 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 = NSLCD_PAM_PERM_DENIED; authzmsg = hostmsg; goto finish; } } cb.sc_response = pam_compare_cb; cb.sc_private = NULL; op->o_tag = LDAP_REQ_COMPARE; op->o_req_dn = hostdn; op->o_req_ndn = hostdn; ava.aa_desc = nssov_pam_svc_ad; ava.aa_value = pi.svc; op->orc_ava = &ava; rc = op->o_bd->be_compare( op, &rs ); if ( cb.sc_private == NULL ) { authzmsg = svcmsg; rc = NSLCD_PAM_PERM_DENIED; goto finish; } 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; SlapReply rs = {REP_RESULT}; op->o_callback = &cb; cb.sc_response = pam_compare_cb; cb.sc_private = NULL; 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 = pi.dn; op->orc_ava = &ava; rc = op->o_bd->be_compare( op, &rs ); if ( cb.sc_private == NULL ) { authzmsg = grpmsg; rc = NSLCD_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)) || ni->ni_pam_template_ad || ni->ni_pam_min_uid || ni->ni_pam_max_uid ) { rc = be_entry_get_rw( op, &pi.dn, NULL, NULL, 0, &e ); if (rc != LDAP_SUCCESS) { rc = NSLCD_PAM_USER_UNKNOWN; goto finish; } } if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) { a = attr_find(e->e_attrs, nssov_pam_host_ad); if (!a || attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_VALUE_OF_SYNTAX, &global_host_bv, NULL, op->o_tmpmemctx )) { rc = NSLCD_PAM_PERM_DENIED; authzmsg = hostmsg; goto finish; } } if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) { a = attr_find(e->e_attrs, nssov_pam_svc_ad); if (!a || attr_valfind( a, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_VALUE_OF_SYNTAX, &pi.svc, NULL, op->o_tmpmemctx )) { rc = NSLCD_PAM_PERM_DENIED; authzmsg = svcmsg; goto finish; } } /* 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_passwd]; a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc); if (!a) { rc = NSLCD_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 = NSLCD_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 = NSLCD_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) pi.uid = a->a_vals[0]; else if (!BER_BVISEMPTY(&ni->ni_pam_template)) pi.uid = ni->ni_pam_template; } rc = NSLCD_PAM_SUCCESS; finish: WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ); WRITE_INT32(fp,NSLCD_RESULT_BEGIN); WRITE_INT32(fp,rc); WRITE_BERVAL(fp,&authzmsg); WRITE_INT32(fp,NSLCD_RESULT_END); if (e) { be_entry_release_r(op, e); } switch (rc) { case NSLCD_PAM_SUCCESS: Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n" ); break; case NSLCD_PAM_PERM_DENIED: Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n", authzmsg.bv_val ? authzmsg.bv_val : "NULL" ); break; default: Debug(LDAP_DEBUG_TRACE, "nssov_pam_authz(): permission denied, rc (%d)\n", rc ); } return 0; } static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action) { int32_t tmpint32; char svcc[256]; char uidc[32]; char ttyc[32]; char rhostc[256]; char ruserc[32]; char sessionID[64]; struct paminfo pi; slap_callback cb = {0}; SlapReply rs = {REP_RESULT}; char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE]; struct berval timestamp, bv[2], *nbv; time_t stamp; Modifications mod; int rc = 0; READ_STRING(fp,uidc); pi.uid.bv_val = uidc; pi.uid.bv_len = tmpint32; READ_STRING(fp,svcc); pi.svc.bv_val = svcc; pi.svc.bv_len = tmpint32; READ_STRING(fp,ruserc); pi.ruser.bv_val = ruserc; pi.ruser.bv_len = tmpint32; READ_STRING(fp,rhostc); pi.rhost.bv_val = rhostc; pi.rhost.bv_len = tmpint32; READ_STRING(fp,ttyc); pi.tty.bv_val = ttyc; pi.tty.bv_len = tmpint32; if (action==NSLCD_ACTION_PAM_SESS_O) { slap_op_time( &op->o_time, &op->o_tincr ); timestamp.bv_len = sizeof(timebuf); timestamp.bv_val = timebuf; stamp = op->o_time; slap_timestamp( &stamp, ×tamp ); } else { READ_STRING(fp,sessionID); timestamp.bv_val = sessionID; timestamp.bv_len = tmpint32; } rc = pam_uid2dn(ni, op, &pi); if (rc) goto done; Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', pi.dn.bv_val ); if (!ni->ni_pam_sessions) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', "pam session(s) not configured, ignored" ); rc = -1; goto done; } { int i, found=0; for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) { if (ni->ni_pam_sessions[i].bv_len != pi.svc.bv_len) continue; if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, pi.svc.bv_val)) { found = 1; break; } } if (!found) { Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): service(%s) not configured, ignored\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', pi.svc.bv_val ); rc = -1; goto done; } } bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + pi.svc.bv_len + pi.tty.bv_len + pi.ruser.bv_len + pi.rhost.bv_len + STRLENOF(" (@)"); bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx ); sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)", timestamp.bv_val, global_host_bv.bv_val, pi.svc.bv_val, pi.tty.bv_val, pi.ruser.bv_val, pi.rhost.bv_val); Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val ); mod.sml_numvals = 1; mod.sml_values = bv; BER_BVZERO(&bv[1]); attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx ); mod.sml_nvalues = nbv; mod.sml_desc = ad_loginStatus; mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD : LDAP_MOD_DELETE; mod.sml_flags = SLAP_MOD_INTERNAL; mod.sml_next = NULL; cb.sc_response = slap_null_cb; op->o_callback = &cb; op->o_tag = LDAP_REQ_MODIFY; op->o_dn = op->o_bd->be_rootdn; op->o_ndn = op->o_bd->be_rootndn; op->orm_modlist = &mod; op->orm_no_opattrs = 1; op->o_req_dn = pi.dn; op->o_req_ndn = pi.dn; if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) { Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): modify op failed\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c' ); rc = -1; } if ( mod.sml_next ) { slap_mods_free( mod.sml_next, 1 ); } ber_bvarray_free_x( nbv, op->o_tmpmemctx ); done:; if (rc == 0) { Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): success\n", action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c' ); } WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,action); WRITE_INT32(fp,NSLCD_RESULT_BEGIN); if (action==NSLCD_ACTION_PAM_SESS_O) WRITE_STRING(fp,timestamp.bv_val); WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op) { return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O); } int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op) { return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C); } int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid) { struct berval npw; int32_t tmpint32; char uidc[32]; char svcc[256]; char ruserc[32]; char rhostc[256]; char ttyc[256]; int asroot; char opwc[256]; char npwc[256]; struct paminfo pi; int rc; READ_STRING(fp,uidc); pi.uid.bv_val = uidc; pi.uid.bv_len = tmpint32; READ_STRING(fp,svcc); pi.svc.bv_val = svcc; pi.svc.bv_len = tmpint32; READ_STRING(fp,ruserc); pi.ruser.bv_val = svcc; pi.ruser.bv_len = tmpint32; READ_STRING(fp,rhostc); pi.rhost.bv_val = svcc; pi.rhost.bv_len = tmpint32; READ_STRING(fp,ttyc); pi.tty.bv_val = svcc; pi.tty.bv_len = tmpint32; READ_INT32(fp, asroot); READ_STRING(fp,opwc); pi.pwd.bv_val = opwc; pi.pwd.bv_len = tmpint32; READ_STRING(fp,npwc); npw.bv_val = npwc; npw.bv_len = tmpint32; rc = pam_uid2dn(ni, op, &pi); if (rc) goto done; Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s %s\n", pi.dn.bv_val ? pi.dn.bv_val : "NULL", pi.uid.bv_val ? pi.uid.bv_val : "NULL", asroot ? "as root" : "as user"); BER_BVZERO(&pi.msg); pi.ispwdmgr = 0; /* nssov_pam prohibits password mod */ if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s (%s)\n", "password_prohibit_message", ni->ni_pam_password_prohibit_message.bv_val ); ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg); rc = NSLCD_PAM_PERM_DENIED; goto done; } if (asroot) { if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n", "pwdmgr not configured" ); ber_str2bv("pwdmgr not configured", 0, 0, &pi.msg); rc = NSLCD_PAM_PERM_DENIED; goto done; } if (calleruid != 0) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s\n", "caller is not root" ); ber_str2bv("only root may do that", 0, 0, &pi.msg); rc = NSLCD_PAM_PERM_DENIED; goto done; } /* root user requesting pwmod */ pi.ispwdmgr = 1; } if (!pi.ispwdmgr && BER_BVISEMPTY(&pi.pwd)) { Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n", "not pwdmgr and old pwd empty" ); ber_str2bv("must provide old password", 0, 0, &pi.msg); rc = NSLCD_PAM_PERM_DENIED; goto done; } 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.dn)) ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, &pi.dn); /* supply old pwd whenever it's given */ 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; if (pi.ispwdmgr) { /* root user changing end-user passwords */ op->o_dn = ni->ni_pam_pwdmgr_dn; op->o_ndn = ni->ni_pam_pwdmgr_dn; } else { /* end-user self-pwd-mod */ 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 = slap_null_cb; 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 = NSLCD_PAM_SUCCESS; else rc = NSLCD_PAM_PERM_DENIED; done:; Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), rc (%d)\n", rc ); WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD); WRITE_INT32(fp,NSLCD_RESULT_BEGIN); WRITE_INT32(fp,rc); WRITE_BERVAL(fp,&pi.msg); return 0; } int nssov_pam_init() { int code = 0; const char *text; if (!ad_loginStatus) code = slap_str2ad("loginStatus", &ad_loginStatus, &text); return code; }