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, ×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
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