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, ×tamp ); 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