]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/pam.c
1fcc0074f83591dbadc516e2e0b0f8c130129977
[openldap] / contrib / slapd-modules / nssov / pam.c
1 /* pam.c - pam processing routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 
4  *
5  * Copyright 2008-2017 The OpenLDAP Foundation.
6  * Portions Copyright 2008 by Howard Chu, Symas Corp.
7  * Portions Copyright 2013 by Ted C. Cheng, Symas Corp.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18
19 #include "nssov.h"
20 #include "lutil.h"
21
22 #undef ldap_debug       /* silence a warning in ldap-int.h */
23 #include "../../../libraries/libldap/ldap-int.h"        /* for ldap_ld_free */
24
25 static int ppolicy_cid;
26 static AttributeDescription *ad_loginStatus;
27
28 struct paminfo {
29         struct berval uid;
30         struct berval dn;
31         struct berval svc;
32         struct berval ruser;
33         struct berval rhost;
34         struct berval tty;
35         struct berval pwd;
36         int authz;
37         struct berval msg;
38         int ispwdmgr;
39 };
40
41 static int pam_bindcb(
42         Operation *op, SlapReply *rs)
43 {
44         struct paminfo *pi = op->o_callback->sc_private;
45         LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
46                 rs->sr_ctrls, NULL);
47         if (ctrl) {
48                 LDAP *ld;
49                 ber_int_t expire, grace;
50                 LDAPPasswordPolicyError error;
51
52                 ldap_create(&ld);
53                 if (ld) {
54                         int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
55                                 &expire,&grace,&error);
56                         if (rc == LDAP_SUCCESS) {
57                                 if (expire >= 0) {
58                                         char *unit = "seconds";
59                                         if (expire > 60) {
60                                                 expire /= 60;
61                                                 unit = "minutes";
62                                         }
63                                         if (expire > 60) {
64                                                 expire /= 60;
65                                                 unit = "hours";
66                                         }
67                                         if (expire > 24) {
68                                                 expire /= 24;
69                                                 unit = "days";
70                                         }
71 #if 0   /* Who warns about expiration so far in advance? */
72                                         if (expire > 7) {
73                                                 expire /= 7;
74                                                 unit = "weeks";
75                                         }
76                                         if (expire > 4) {
77                                                 expire /= 4;
78                                                 unit = "months";
79                                         }
80                                         if (expire > 12) {
81                                                 expire /= 12;
82                                                 unit = "years";
83                                         }
84 #endif
85                                         pi->msg.bv_len = sprintf(pi->msg.bv_val,
86                                                 "\nWARNING: Password expires in %d %s\n", expire, unit);
87                                 } else if (grace > 0) {
88                                         pi->msg.bv_len = sprintf(pi->msg.bv_val,
89                                                 "Password expired; %d grace logins remaining",
90                                                 grace);
91                                         pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
92                                 } else if (error != PP_noError) {
93                                         ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
94                                                 &pi->msg);
95                                         switch (error) {
96                                         case PP_passwordExpired:
97                                                 /* report this during authz */
98                                                 rs->sr_err = LDAP_SUCCESS;
99                                                 /* fallthru */
100                                         case PP_changeAfterReset:
101                                                 pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
102                                         }
103                                 }
104                         }
105                         ldap_ld_free(ld,0,NULL,NULL);
106                 }
107         }
108         return LDAP_SUCCESS;
109 }
110
111 static int pam_uid2dn(nssov_info *ni, Operation *op,
112         struct paminfo *pi)
113 {
114         struct berval sdn;
115
116         BER_BVZERO(&pi->dn);
117
118         if (!isvalidusername(&pi->uid)) {
119                 Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n",
120                         pi->uid.bv_val ? pi->uid.bv_val : "NULL",0,0);
121                 return NSLCD_PAM_USER_UNKNOWN;
122         }
123
124         if (ni->ni_pam_opts & NI_PAM_SASL2DN) {
125                 int hlen = global_host_bv.bv_len;
126
127                 /* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
128                 sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen +
129                         STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
130                 sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
131                 sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth",
132                         pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val);
133                 slap_sasl2dn(op, &sdn, &pi->dn, 0);
134                 op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
135         }
136
137         /* If no luck, do a basic uid search */
138         if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
139                 nssov_uid2dn(op, ni, &pi->uid, &pi->dn);
140                 if (!BER_BVISEMPTY(&pi->dn)) {
141                         sdn = pi->dn;
142                         dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx );
143                 }
144         }
145         if (BER_BVISEMPTY(&pi->dn)) {
146                 return NSLCD_PAM_USER_UNKNOWN;
147         }
148         return 0;
149 }
150
151 int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
152         struct paminfo *pi)
153 {
154         int rc;
155         slap_callback cb = {0};
156         SlapReply rs = {REP_RESULT};
157
158         pi->msg.bv_val = pi->pwd.bv_val;
159         pi->msg.bv_len = 0;
160         pi->authz = NSLCD_PAM_SUCCESS;
161
162         if (!pi->ispwdmgr) {
163
164                 rc = pam_uid2dn(ni, op, pi);
165                 if (rc) goto finish;
166
167                 if (BER_BVISEMPTY(&pi->pwd)) {
168                         rc = NSLCD_PAM_PERM_DENIED;
169                         goto finish;
170                 }
171
172                 /* Should only need to do this once at open time, but there's always
173                  * the possibility that ppolicy will get loaded later.
174                  */
175                 if (!ppolicy_cid) {
176                         rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
177                                 &ppolicy_cid);
178                 }
179                 /* of course, 0 is a valid cid, but it won't be ppolicy... */
180                 if (ppolicy_cid) {
181                         op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
182                 }
183         }
184
185         cb.sc_response = pam_bindcb;
186         cb.sc_private = pi;
187         op->o_callback = &cb;
188         op->o_dn.bv_val[0] = 0;
189         op->o_dn.bv_len = 0;
190         op->o_ndn.bv_val[0] = 0;
191         op->o_ndn.bv_len = 0;
192         op->o_tag = LDAP_REQ_BIND;
193         op->o_protocol = LDAP_VERSION3;
194         op->orb_method = LDAP_AUTH_SIMPLE;
195         op->orb_cred = pi->pwd;
196         op->o_req_dn = pi->dn;
197         op->o_req_ndn = pi->dn;
198         slap_op_time( &op->o_time, &op->o_tincr );
199         rc = op->o_bd->be_bind( op, &rs );
200         memset(pi->pwd.bv_val,0,pi->pwd.bv_len);
201         /* quirk: on successful bind, caller has to send result. we need
202          * to make sure callbacks run.
203          */
204         if (rc == LDAP_SUCCESS)
205                 send_ldap_result(op, &rs);
206         switch(rs.sr_err) {
207         case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break;
208         case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break;
209         default: rc = NSLCD_PAM_AUTH_ERR; break;
210         }
211 finish:
212         Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n",
213                 pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc, 0);
214         return rc;
215 }
216
217 int pam_authc(nssov_info *ni,TFILE *fp,Operation *op,uid_t calleruid)
218 {
219         int32_t tmpint32;
220         int rc;
221         char uidc[32];
222         char svcc[256];
223         char ruserc[32];
224         char rhostc[256];
225         char ttyc[256];
226         char pwdc[256];
227         struct paminfo pi;
228
229
230         READ_STRING(fp,uidc);
231         pi.uid.bv_val = uidc;
232         pi.uid.bv_len = tmpint32;
233         READ_STRING(fp,svcc);
234         pi.svc.bv_val = svcc;
235         pi.svc.bv_len = tmpint32;
236         READ_STRING(fp,ruserc);
237         pi.ruser.bv_val = ruserc;
238         pi.ruser.bv_len = tmpint32;
239         READ_STRING(fp,rhostc);
240         pi.rhost.bv_val = rhostc;
241         pi.rhost.bv_len = tmpint32;
242         READ_STRING(fp,ttyc);
243         pi.tty.bv_val = ttyc;
244         pi.tty.bv_len = tmpint32;
245         READ_STRING(fp,pwdc);
246         pi.pwd.bv_val = pwdc;
247         pi.pwd.bv_len = tmpint32;
248
249         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",
250                         pi.uid.bv_val ? pi.uid.bv_val : "NULL",0,0);
251
252         BER_BVZERO(&pi.msg);
253         pi.ispwdmgr = 0;
254
255         /* if service is "passwd" and "nssov-pam-password-prohibit-message */
256         /* is set, deny the auth request */
257         if (!strcmp(svcc, "passwd") &&
258                 !BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
259                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n",
260                         "password_prohibit_message for passwd",
261                         ni->ni_pam_password_prohibit_message.bv_val,0);
262                 ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
263                 pi.authz = NSLCD_PAM_PERM_DENIED;
264                 rc = NSLCD_PAM_PERM_DENIED;
265                 goto finish;
266         }
267
268         /* if username is null, pwdmgr password preliminary check */
269         if (BER_BVISEMPTY(&pi.uid)) {
270                 if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
271                         /* pwdmgr dn not configured */
272                         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
273                                 "pwdmgr dn not configured", 0, 0);
274                         ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg);
275                         pi.authz = NSLCD_PAM_PERM_DENIED;
276                         rc = NSLCD_PAM_PERM_DENIED;
277                         goto finish;
278                 } else if (calleruid != 0) {
279                         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
280                                 "caller is not root", 0, 0);
281                         ber_str2bv("only root may do that", 0, 0, &pi.msg);
282                         pi.authz = NSLCD_PAM_PERM_DENIED;
283                         rc = NSLCD_PAM_PERM_DENIED;
284                         goto finish;
285                 } else {
286                         /* use pwdmgr dn */
287                         ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn);
288                 }
289
290                 /* use pwdmgr pwd if configured */
291                 if (BER_BVISEMPTY(&pi.pwd)) {
292                         if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) {
293                                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
294                                         "no pwdmgr pwd", 0, 0);
295                                 ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg);
296                                 pi.authz = NSLCD_PAM_PERM_DENIED;
297                                 rc = NSLCD_PAM_PERM_DENIED;
298                                 goto finish;
299                         }
300                         /* use configured pwdmgr pwd */
301                         memset((void *) pwdc, 0, 256);
302                         strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val,
303                                         ni->ni_pam_pwdmgr_pwd.bv_len);
304                         pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len;
305                 }
306                 pi.ispwdmgr = 1;
307         }
308
309
310         rc = pam_do_bind(ni, fp, op, &pi);
311
312 finish:
313         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n",
314                 pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc,0);
315         WRITE_INT32(fp,NSLCD_VERSION);
316         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
317         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
318         WRITE_INT32(fp,rc);
319         WRITE_BERVAL(fp,&pi.uid);
320         WRITE_INT32(fp,pi.authz);       /* authz */
321         WRITE_BERVAL(fp,&pi.msg);       /* authzmsg */
322         WRITE_INT32(fp,NSLCD_RESULT_END);
323         return 0;
324 }
325
326 static struct berval grpmsg =
327         BER_BVC("Access denied by group check");
328 static struct berval hostmsg =
329         BER_BVC("Access denied for this host");
330 static struct berval svcmsg =
331         BER_BVC("Access denied for this service");
332 static struct berval uidmsg =
333         BER_BVC("Access denied by UID check");
334
335 static int pam_compare_cb(Operation *op, SlapReply *rs)
336 {
337         if (rs->sr_err == LDAP_COMPARE_TRUE)
338                 op->o_callback->sc_private = (void *)1;
339         return LDAP_SUCCESS;
340 }
341
342 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
343 {
344         struct berval authzmsg = BER_BVNULL;
345         int32_t tmpint32;
346         char uidc[32];
347         char svcc[256];
348         char ruserc[32];
349         char rhostc[256];
350         char ttyc[256];
351         int rc;
352         struct paminfo pi;
353         Entry *e = NULL;
354         Attribute *a;
355         slap_callback cb = {0};
356
357         READ_STRING(fp,uidc);
358         pi.uid.bv_val = uidc;
359         pi.uid.bv_len = tmpint32;
360         READ_STRING(fp,svcc);
361         pi.svc.bv_val = svcc;
362         pi.svc.bv_len = tmpint32;
363         READ_STRING(fp,ruserc);
364         pi.ruser.bv_val = ruserc;
365         pi.ruser.bv_len = tmpint32;
366         READ_STRING(fp,rhostc);
367         pi.rhost.bv_val = rhostc;
368         pi.rhost.bv_len = tmpint32;
369         READ_STRING(fp,ttyc);
370         pi.tty.bv_val = ttyc;
371         pi.tty.bv_len = tmpint32;
372
373         rc = pam_uid2dn(ni, op, &pi);
374         if (rc) goto finish;
375
376         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",
377                         pi.dn.bv_val ? pi.dn.bv_val : "NULL",0,0);
378
379         /* See if they have access to the host and service */
380         if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) {
381                 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
382                 struct berval hostdn = BER_BVNULL;
383                 struct berval odn = op->o_ndn;
384                 SlapReply rs = {REP_RESULT};
385                 op->o_dn = pi.dn;
386                 op->o_ndn = pi.dn;
387                 {
388                         nssov_mapinfo *mi = &ni->ni_maps[NM_host];
389                         char fbuf[1024];
390                         struct berval filter = {sizeof(fbuf),fbuf};
391                         SlapReply rs2 = {REP_RESULT};
392
393                         /* Lookup the host entry */
394                         nssov_filter_byname(mi,0,&global_host_bv,&filter);
395                         cb.sc_private = &hostdn;
396                         cb.sc_response = nssov_name2dn_cb;
397                         op->o_callback = &cb;
398                         op->o_req_dn = mi->mi_base;
399                         op->o_req_ndn = mi->mi_base;
400                         op->ors_scope = mi->mi_scope;
401                         op->ors_filterstr = filter;
402                         op->ors_filter = str2filter_x(op, filter.bv_val);
403                         op->ors_attrs = slap_anlist_no_attrs;
404                         op->ors_tlimit = SLAP_NO_LIMIT;
405                         op->ors_slimit = 2;
406                         rc = op->o_bd->be_search(op, &rs2);
407                         filter_free_x(op, op->ors_filter, 1);
408
409                         if (BER_BVISEMPTY(&hostdn) &&
410                                 !BER_BVISEMPTY(&ni->ni_pam_defhost)) {
411                                 filter.bv_len = sizeof(fbuf);
412                                 filter.bv_val = fbuf;
413                                 rs_reinit(&rs2, REP_RESULT);
414                                 nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter);
415                                 op->ors_filterstr = filter;
416                                 op->ors_filter = str2filter_x(op, filter.bv_val);
417                                 rc = op->o_bd->be_search(op, &rs2);
418                                 filter_free_x(op, op->ors_filter, 1);
419                         }
420
421                         /* no host entry, no default host -> deny */
422                         if (BER_BVISEMPTY(&hostdn)) {
423                                 rc = NSLCD_PAM_PERM_DENIED;
424                                 authzmsg = hostmsg;
425                                 goto finish;
426                         }
427                 }
428
429                 cb.sc_response = pam_compare_cb;
430                 cb.sc_private = NULL;
431                 op->o_tag = LDAP_REQ_COMPARE;
432                 op->o_req_dn = hostdn;
433                 op->o_req_ndn = hostdn;
434                 ava.aa_desc = nssov_pam_svc_ad;
435                 ava.aa_value = pi.svc;
436                 op->orc_ava = &ava;
437                 rc = op->o_bd->be_compare( op, &rs );
438                 if ( cb.sc_private == NULL ) {
439                         authzmsg = svcmsg;
440                         rc = NSLCD_PAM_PERM_DENIED;
441                         goto finish;
442                 }
443                 op->o_dn = odn;
444                 op->o_ndn = odn;
445         }
446
447         /* See if they're a member of the group */
448         if ((ni->ni_pam_opts & NI_PAM_USERGRP) &&
449                 !BER_BVISEMPTY(&ni->ni_pam_group_dn) &&
450                 ni->ni_pam_group_ad) {
451                 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
452                 SlapReply rs = {REP_RESULT};
453                 op->o_callback = &cb;
454                 cb.sc_response = pam_compare_cb;
455                 cb.sc_private = NULL;
456                 op->o_tag = LDAP_REQ_COMPARE;
457                 op->o_req_dn = ni->ni_pam_group_dn;
458                 op->o_req_ndn = ni->ni_pam_group_dn;
459                 ava.aa_desc = ni->ni_pam_group_ad;
460                 ava.aa_value = pi.dn;
461                 op->orc_ava = &ava;
462                 rc = op->o_bd->be_compare( op, &rs );
463                 if ( cb.sc_private == NULL ) {
464                         authzmsg = grpmsg;
465                         rc = NSLCD_PAM_PERM_DENIED;
466                         goto finish;
467                 }
468         }
469
470         /* We need to check the user's entry for these bits */
471         if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) ||
472                 ni->ni_pam_template_ad ||
473                 ni->ni_pam_min_uid || ni->ni_pam_max_uid ) {
474                 rc = be_entry_get_rw( op, &pi.dn, NULL, NULL, 0, &e );
475                 if (rc != LDAP_SUCCESS) {
476                         rc = NSLCD_PAM_USER_UNKNOWN;
477                         goto finish;
478                 }
479         }
480         if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) {
481                 a = attr_find(e->e_attrs, nssov_pam_host_ad);
482                 if (!a || attr_valfind( a,
483                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
484                         SLAP_MR_VALUE_OF_SYNTAX,
485                         &global_host_bv, NULL, op->o_tmpmemctx )) {
486                         rc = NSLCD_PAM_PERM_DENIED;
487                         authzmsg = hostmsg;
488                         goto finish;
489                 }
490         }
491         if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) {
492                 a = attr_find(e->e_attrs, nssov_pam_svc_ad);
493                 if (!a || attr_valfind( a,
494                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
495                         SLAP_MR_VALUE_OF_SYNTAX,
496                         &pi.svc, NULL, op->o_tmpmemctx )) {
497                         rc = NSLCD_PAM_PERM_DENIED;
498                         authzmsg = svcmsg;
499                         goto finish;
500                 }
501         }
502
503 /* from passwd.c */
504 #define UIDN_KEY        2
505
506         if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) {
507                 int id;
508                 char *tmp;
509                 nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
510                 a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc);
511                 if (!a) {
512                         rc = NSLCD_PAM_PERM_DENIED;
513                         authzmsg = uidmsg;
514                         goto finish;
515                 }
516                 id = (int)strtol(a->a_vals[0].bv_val,&tmp,0);
517                 if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') {
518                         rc = NSLCD_PAM_PERM_DENIED;
519                         authzmsg = uidmsg;
520                         goto finish;
521                 }
522                 if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) ||
523                         (ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) {
524                         rc = NSLCD_PAM_PERM_DENIED;
525                         authzmsg = uidmsg;
526                         goto finish;
527                 }
528         }
529
530         if (ni->ni_pam_template_ad) {
531                 a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
532                 if (a)
533                         pi.uid = a->a_vals[0];
534                 else if (!BER_BVISEMPTY(&ni->ni_pam_template))
535                         pi.uid = ni->ni_pam_template;
536         }
537         rc = NSLCD_PAM_SUCCESS;
538
539 finish:
540         WRITE_INT32(fp,NSLCD_VERSION);
541         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
542         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
543         WRITE_INT32(fp,rc);
544         WRITE_BERVAL(fp,&authzmsg);
545         WRITE_INT32(fp,NSLCD_RESULT_END);
546         if (e) {
547                 be_entry_release_r(op, e);
548         }
549         switch (rc) {
550         case NSLCD_PAM_SUCCESS:
551                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n", 0,0,0);
552                 break;
553         case NSLCD_PAM_PERM_DENIED:
554                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n",
555                         authzmsg.bv_val ? authzmsg.bv_val : "NULL",0,0);
556                 break;
557         default:
558                 Debug(LDAP_DEBUG_TRACE,
559                         "nssov_pam_authz(): permission denied, rc (%d)\n",
560                         rc, 0, 0);
561         }
562         return 0;
563 }
564
565 static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
566 {
567         int32_t tmpint32;
568         char svcc[256];
569         char uidc[32];
570         char ttyc[32];
571         char rhostc[256];
572         char ruserc[32];
573         char sessionID[64];
574         struct paminfo pi;
575         slap_callback cb = {0};
576         SlapReply rs = {REP_RESULT};
577         char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
578         struct berval timestamp, bv[2], *nbv;
579         time_t stamp;
580         Modifications mod;
581         int rc = 0;
582
583         READ_STRING(fp,uidc);
584         pi.uid.bv_val = uidc;
585         pi.uid.bv_len = tmpint32;
586         READ_STRING(fp,svcc);
587         pi.svc.bv_val = svcc;
588         pi.svc.bv_len = tmpint32;
589         READ_STRING(fp,ruserc);
590         pi.ruser.bv_val = ruserc;
591         pi.ruser.bv_len = tmpint32;
592         READ_STRING(fp,rhostc);
593         pi.rhost.bv_val = rhostc;
594         pi.rhost.bv_len = tmpint32;
595         READ_STRING(fp,ttyc);
596         pi.tty.bv_val = ttyc;
597         pi.tty.bv_len = tmpint32;
598
599         if (action==NSLCD_ACTION_PAM_SESS_O) {
600                 slap_op_time( &op->o_time, &op->o_tincr );
601                 timestamp.bv_len = sizeof(timebuf);
602                 timestamp.bv_val = timebuf;
603                 stamp = op->o_time;
604                 slap_timestamp( &stamp, &timestamp );
605         } else {
606                 READ_STRING(fp,sessionID);
607                 timestamp.bv_val = sessionID;
608                 timestamp.bv_len = tmpint32;
609         }
610
611         rc = pam_uid2dn(ni, op, &pi);
612         if (rc) goto done;
613
614         Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n",
615                 action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', pi.dn.bv_val,0);
616
617         if (!ni->ni_pam_sessions) {
618                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
619                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
620                         "pam session(s) not configured, ignored",0);
621                 rc = -1;
622                 goto done;
623         }
624
625         {
626                 int i, found=0;
627                 for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) {
628                         if (ni->ni_pam_sessions[i].bv_len != pi.svc.bv_len)
629                                 continue;
630                         if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, pi.svc.bv_val)) {
631                                 found = 1;
632                                 break;
633                         }
634                 }
635                 if (!found) {
636                         Debug(LDAP_DEBUG_TRACE,
637                                 "nssov_pam_sess_%c(): service(%s) not configured, ignored\n",
638                                 action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
639                                 pi.svc.bv_val,0);
640                         rc = -1;
641                         goto done;
642                 }
643         }
644
645         bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + pi.svc.bv_len +
646                 pi.tty.bv_len + pi.ruser.bv_len + pi.rhost.bv_len + STRLENOF("    (@)");
647         bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx );
648         sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)",
649                 timestamp.bv_val, global_host_bv.bv_val, pi.svc.bv_val, pi.tty.bv_val,
650                 pi.ruser.bv_val, pi.rhost.bv_val);
651
652         Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n",
653                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val,0);
654         
655         mod.sml_numvals = 1;
656         mod.sml_values = bv;
657         BER_BVZERO(&bv[1]);
658         attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx );
659         mod.sml_nvalues = nbv;
660         mod.sml_desc = ad_loginStatus;
661         mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD :
662                 LDAP_MOD_DELETE;
663         mod.sml_flags = SLAP_MOD_INTERNAL;
664         mod.sml_next = NULL;
665
666         cb.sc_response = slap_null_cb;
667         op->o_callback = &cb;
668         op->o_tag = LDAP_REQ_MODIFY;
669         op->o_dn = op->o_bd->be_rootdn;
670         op->o_ndn = op->o_bd->be_rootndn;
671         op->orm_modlist = &mod;
672         op->orm_no_opattrs = 1;
673         op->o_req_dn = pi.dn;
674         op->o_req_ndn = pi.dn;
675         if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) {
676                 Debug(LDAP_DEBUG_TRACE,
677                         "nssov_pam_sess_%c(): modify op failed\n",
678                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
679                         0,0);
680                 rc = -1;
681         }
682
683         if ( mod.sml_next ) {
684                 slap_mods_free( mod.sml_next, 1 );
685         }
686         ber_bvarray_free_x( nbv, op->o_tmpmemctx );
687
688 done:;
689
690         if (rc == 0) {
691                 Debug(LDAP_DEBUG_TRACE,
692                         "nssov_pam_sess_%c(): success\n",
693                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
694                         0,0);
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
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
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
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,0);
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", 0, 0);
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", 0, 0);
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", 0, 0);
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, 0, 0);
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
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 }