]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/pam.c
577ae9adcc6d379e005b4310e51770fd1283708c
[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-2015 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 static int ppolicy_cid;
23 static AttributeDescription *ad_loginStatus;
24
25 struct paminfo {
26         struct berval uid;
27         struct berval dn;
28         struct berval svc;
29         struct berval pwd;
30         int authz;
31         struct berval msg;
32         int ispwdmgr;
33 };
34
35 static int pam_bindcb(
36         Operation *op, SlapReply *rs)
37 {
38         struct paminfo *pi = op->o_callback->sc_private;
39         LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
40                 rs->sr_ctrls, NULL);
41         if (ctrl) {
42                 LDAP *ld;
43                 ber_int_t expire, grace;
44                 LDAPPasswordPolicyError error;
45
46                 ldap_create(&ld);
47                 if (ld) {
48                         int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
49                                 &expire,&grace,&error);
50                         if (rc == LDAP_SUCCESS) {
51                                 if (expire >= 0) {
52                                         char *unit = "seconds";
53                                         if (expire > 60) {
54                                                 expire /= 60;
55                                                 unit = "minutes";
56                                         }
57                                         if (expire > 60) {
58                                                 expire /= 60;
59                                                 unit = "hours";
60                                         }
61                                         if (expire > 24) {
62                                                 expire /= 24;
63                                                 unit = "days";
64                                         }
65 #if 0   /* Who warns about expiration so far in advance? */
66                                         if (expire > 7) {
67                                                 expire /= 7;
68                                                 unit = "weeks";
69                                         }
70                                         if (expire > 4) {
71                                                 expire /= 4;
72                                                 unit = "months";
73                                         }
74                                         if (expire > 12) {
75                                                 expire /= 12;
76                                                 unit = "years";
77                                         }
78 #endif
79                                         pi->msg.bv_len = sprintf(pi->msg.bv_val,
80                                                 "\nWARNING: Password expires in %d %s\n", expire, unit);
81                                 } else if (grace > 0) {
82                                         pi->msg.bv_len = sprintf(pi->msg.bv_val,
83                                                 "Password expired; %d grace logins remaining",
84                                                 grace);
85                                         pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
86                                 } else if (error != PP_noError) {
87                                         ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
88                                                 &pi->msg);
89                                         switch (error) {
90                                         case PP_passwordExpired:
91                                                 /* report this during authz */
92                                                 rs->sr_err = LDAP_SUCCESS;
93                                                 /* fallthru */
94                                         case PP_changeAfterReset:
95                                                 pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD;
96                                         }
97                                 }
98                         }
99                         ldap_ld_free(ld,0,NULL,NULL);
100                 }
101         }
102         return LDAP_SUCCESS;
103 }
104
105 static int pam_uid2dn(nssov_info *ni, Operation *op,
106         struct paminfo *pi)
107 {
108         struct berval sdn;
109
110         BER_BVZERO(&pi->dn);
111
112         if (!isvalidusername(&pi->uid)) {
113                 Debug(LDAP_DEBUG_ANY,"nssov_pam_uid2dn(%s): invalid user name\n",
114                         pi->uid.bv_val ? pi->uid.bv_val : "NULL",0,0);
115                 return NSLCD_PAM_USER_UNKNOWN;
116         }
117
118         if (ni->ni_pam_opts & NI_PAM_SASL2DN) {
119                 int hlen = global_host_bv.bv_len;
120
121                 /* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
122                 sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen +
123                         STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
124                 sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
125                 sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth",
126                         pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val);
127                 slap_sasl2dn(op, &sdn, &pi->dn, 0);
128                 op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
129         }
130
131         /* If no luck, do a basic uid search */
132         if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) {
133                 nssov_uid2dn(op, ni, &pi->uid, &pi->dn);
134                 if (!BER_BVISEMPTY(&pi->dn)) {
135                         sdn = pi->dn;
136                         dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx );
137                 }
138         }
139         if (BER_BVISEMPTY(&pi->dn)) {
140                 return NSLCD_PAM_USER_UNKNOWN;
141         }
142         return 0;
143 }
144
145 int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op,
146         struct paminfo *pi)
147 {
148         int rc;
149         slap_callback cb = {0};
150         SlapReply rs = {REP_RESULT};
151
152         pi->msg.bv_val = pi->pwd.bv_val;
153         pi->msg.bv_len = 0;
154         pi->authz = NSLCD_PAM_SUCCESS;
155
156         if (!pi->ispwdmgr) {
157
158                 BER_BVZERO(&pi->dn);
159                 rc = pam_uid2dn(ni, op, pi);
160                 if (rc) goto finish;
161
162                 if (BER_BVISEMPTY(&pi->pwd)) {
163                         rc = NSLCD_PAM_PERM_DENIED;
164                         goto finish;
165                 }
166
167                 /* Should only need to do this once at open time, but there's always
168                  * the possibility that ppolicy will get loaded later.
169                  */
170                 if (!ppolicy_cid) {
171                         rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
172                                 &ppolicy_cid);
173                 }
174                 /* of course, 0 is a valid cid, but it won't be ppolicy... */
175                 if (ppolicy_cid) {
176                         op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
177                 }
178         }
179
180         cb.sc_response = pam_bindcb;
181         cb.sc_private = pi;
182         op->o_callback = &cb;
183         op->o_dn.bv_val[0] = 0;
184         op->o_dn.bv_len = 0;
185         op->o_ndn.bv_val[0] = 0;
186         op->o_ndn.bv_len = 0;
187         op->o_tag = LDAP_REQ_BIND;
188         op->o_protocol = LDAP_VERSION3;
189         op->orb_method = LDAP_AUTH_SIMPLE;
190         op->orb_cred = pi->pwd;
191         op->o_req_dn = pi->dn;
192         op->o_req_ndn = pi->dn;
193         slap_op_time( &op->o_time, &op->o_tincr );
194         rc = op->o_bd->be_bind( op, &rs );
195         memset(pi->pwd.bv_val,0,pi->pwd.bv_len);
196         /* quirk: on successful bind, caller has to send result. we need
197          * to make sure callbacks run.
198          */
199         if (rc == LDAP_SUCCESS)
200                 send_ldap_result(op, &rs);
201         switch(rs.sr_err) {
202         case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break;
203         case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break;
204         default: rc = NSLCD_PAM_AUTH_ERR; break;
205         }
206 finish:
207         Debug(LDAP_DEBUG_ANY,"pam_do_bind (%s): rc (%d)\n",
208                 pi->dn.bv_val ? pi->dn.bv_val : "NULL", rc, 0);
209         return rc;
210 }
211
212 int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
213 {
214         int32_t tmpint32;
215         int rc;
216         slap_callback cb = {0};
217         char dnc[1024];
218         char uidc[32];
219         char svcc[256];
220         char pwdc[256];
221         struct berval sdn, dn;
222         struct paminfo pi;
223
224
225         READ_STRING(fp,uidc);
226         pi.uid.bv_val = uidc;
227         pi.uid.bv_len = tmpint32;
228         READ_STRING(fp,dnc);
229         pi.dn.bv_val = dnc;
230         pi.dn.bv_len = tmpint32;
231         READ_STRING(fp,svcc);
232         pi.svc.bv_val = svcc;
233         pi.svc.bv_len = tmpint32;
234         READ_STRING(fp,pwdc);
235         pi.pwd.bv_val = pwdc;
236         pi.pwd.bv_len = tmpint32;
237
238         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",
239                         pi.uid.bv_val ? pi.uid.bv_val : "NULL",0,0);
240
241         pi.ispwdmgr = 0;
242
243         /* if service is "passwd" and "nssov-pam-password-prohibit-message */
244         /* is set, deny the auth request */
245         if (!strcmp(svcc, "passwd") &&
246                 !BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
247                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(): %s (%s)\n",
248                         "password_prohibit_message for passwd",
249                         ni->ni_pam_password_prohibit_message.bv_val,0);
250                 ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
251                 pi.authz = NSLCD_PAM_PERM_DENIED;
252                 rc = NSLCD_PAM_PERM_DENIED;
253                 goto finish;
254         }
255
256         /* if username is null, pwdmgr password preliminary check */
257         if (BER_BVISEMPTY(&pi.uid)) {
258                 if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
259                         /* pwdmgr dn not configured */
260                         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
261                                 "pwdmgr dn not configured", 0, 0);
262                         ber_str2bv("pwdmgr dn not configured", 0, 0, &pi.msg);
263                         pi.authz = NSLCD_PAM_PERM_DENIED;
264                         rc = NSLCD_PAM_PERM_DENIED;
265                         goto finish;
266                 } else {
267                         /* use pwdmgr dn */
268                         ber_str2bv(ni->ni_pam_pwdmgr_dn.bv_val, 0, 0, &pi.dn);
269                 }
270
271                 /* use pwdmgr pwd if configured */
272                 if (BER_BVISEMPTY(&pi.pwd)) {
273                         if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_pwd)) {
274                                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(prelim check): %s\n",
275                                         "no pwdmgr pwd", 0, 0);
276                                 ber_str2bv("pwdmgr pwd not configured", 0, 0, &pi.msg);
277                                 pi.authz = NSLCD_PAM_PERM_DENIED;
278                                 rc = NSLCD_PAM_PERM_DENIED;
279                                 goto finish;
280                         }
281                         /* use configured pwdmgr pwd */
282                         memset((void *) pwdc, 0, 256);
283                         strncpy(pi.pwd.bv_val, ni->ni_pam_pwdmgr_pwd.bv_val,
284                                         ni->ni_pam_pwdmgr_pwd.bv_len);
285                         pi.pwd.bv_len = ni->ni_pam_pwdmgr_pwd.bv_len;
286                 }
287                 pi.ispwdmgr = 1;
288         }
289
290
291         rc = pam_do_bind(ni, fp, op, &pi);
292
293 finish:
294         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s): rc (%d)\n",
295                 pi.dn.bv_val ? pi.dn.bv_val : "NULL",rc,0);
296         WRITE_INT32(fp,NSLCD_VERSION);
297         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
298         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
299         WRITE_BERVAL(fp,&pi.uid);
300         WRITE_BERVAL(fp,&pi.dn);
301         WRITE_INT32(fp,rc);
302         WRITE_INT32(fp,pi.authz);       /* authz */
303         WRITE_BERVAL(fp,&pi.msg);       /* authzmsg */
304         return 0;
305 }
306
307 static struct berval grpmsg =
308         BER_BVC("Access denied by group check");
309 static struct berval hostmsg =
310         BER_BVC("Access denied for this host");
311 static struct berval svcmsg =
312         BER_BVC("Access denied for this service");
313 static struct berval uidmsg =
314         BER_BVC("Access denied by UID check");
315
316 static int pam_compare_cb(Operation *op, SlapReply *rs)
317 {
318         if (rs->sr_err == LDAP_COMPARE_TRUE)
319                 op->o_callback->sc_private = (void *)1;
320         return LDAP_SUCCESS;
321 }
322
323 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
324 {
325         struct berval dn, uid, svc, ruser, rhost, tty;
326         struct berval authzmsg = BER_BVNULL;
327         int32_t tmpint32;
328         char dnc[1024];
329         char uidc[32];
330         char svcc[256];
331         char ruserc[32];
332         char rhostc[256];
333         char ttyc[256];
334         int rc;
335         Entry *e = NULL;
336         Attribute *a;
337         slap_callback cb = {0};
338
339         READ_STRING(fp,uidc);
340         uid.bv_val = uidc;
341         uid.bv_len = tmpint32;
342         READ_STRING(fp,dnc);
343         dn.bv_val = dnc;
344         dn.bv_len = tmpint32;
345         READ_STRING(fp,svcc);
346         svc.bv_val = svcc;
347         svc.bv_len = tmpint32;
348         READ_STRING(fp,ruserc);
349         ruser.bv_val = ruserc;
350         ruser.bv_len = tmpint32;
351         READ_STRING(fp,rhostc);
352         rhost.bv_val = rhostc;
353         rhost.bv_len = tmpint32;
354         READ_STRING(fp,ttyc);
355         tty.bv_val = ttyc;
356         tty.bv_len = tmpint32;
357
358         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",
359                         dn.bv_val ? dn.bv_val : "NULL",0,0);
360
361         /* If we didn't do authc, we don't have a DN yet */
362         if (BER_BVISEMPTY(&dn)) {
363                 struct paminfo pi;
364                 pi.uid = uid;
365                 pi.svc = svc;
366
367                 rc = pam_uid2dn(ni, op, &pi);
368                 if (rc) goto finish;
369                 dn = pi.dn;
370         }
371
372         /* See if they have access to the host and service */
373         if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) {
374                 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
375                 struct berval hostdn = BER_BVNULL;
376                 struct berval odn = op->o_ndn;
377                 SlapReply rs = {REP_RESULT};
378                 op->o_dn = dn;
379                 op->o_ndn = dn;
380                 {
381                         nssov_mapinfo *mi = &ni->ni_maps[NM_host];
382                         char fbuf[1024];
383                         struct berval filter = {sizeof(fbuf),fbuf};
384                         SlapReply rs2 = {REP_RESULT};
385
386                         /* Lookup the host entry */
387                         nssov_filter_byname(mi,0,&global_host_bv,&filter);
388                         cb.sc_private = &hostdn;
389                         cb.sc_response = nssov_name2dn_cb;
390                         op->o_callback = &cb;
391                         op->o_req_dn = mi->mi_base;
392                         op->o_req_ndn = mi->mi_base;
393                         op->ors_scope = mi->mi_scope;
394                         op->ors_filterstr = filter;
395                         op->ors_filter = str2filter_x(op, filter.bv_val);
396                         op->ors_attrs = slap_anlist_no_attrs;
397                         op->ors_tlimit = SLAP_NO_LIMIT;
398                         op->ors_slimit = 2;
399                         rc = op->o_bd->be_search(op, &rs2);
400                         filter_free_x(op, op->ors_filter, 1);
401
402                         if (BER_BVISEMPTY(&hostdn) &&
403                                 !BER_BVISEMPTY(&ni->ni_pam_defhost)) {
404                                 filter.bv_len = sizeof(fbuf);
405                                 filter.bv_val = fbuf;
406                                 rs_reinit(&rs2, REP_RESULT);
407                                 nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter);
408                                 op->ors_filterstr = filter;
409                                 op->ors_filter = str2filter_x(op, filter.bv_val);
410                                 rc = op->o_bd->be_search(op, &rs2);
411                                 filter_free_x(op, op->ors_filter, 1);
412                         }
413
414                         /* no host entry, no default host -> deny */
415                         if (BER_BVISEMPTY(&hostdn)) {
416                                 rc = NSLCD_PAM_PERM_DENIED;
417                                 authzmsg = hostmsg;
418                                 goto finish;
419                         }
420                 }
421
422                 cb.sc_response = pam_compare_cb;
423                 cb.sc_private = NULL;
424                 op->o_tag = LDAP_REQ_COMPARE;
425                 op->o_req_dn = hostdn;
426                 op->o_req_ndn = hostdn;
427                 ava.aa_desc = nssov_pam_svc_ad;
428                 ava.aa_value = svc;
429                 op->orc_ava = &ava;
430                 rc = op->o_bd->be_compare( op, &rs );
431                 if ( cb.sc_private == NULL ) {
432                         authzmsg = svcmsg;
433                         rc = NSLCD_PAM_PERM_DENIED;
434                         goto finish;
435                 }
436                 op->o_dn = odn;
437                 op->o_ndn = odn;
438         }
439
440         /* See if they're a member of the group */
441         if ((ni->ni_pam_opts & NI_PAM_USERGRP) &&
442                 !BER_BVISEMPTY(&ni->ni_pam_group_dn) &&
443                 ni->ni_pam_group_ad) {
444                 AttributeAssertion ava = ATTRIBUTEASSERTION_INIT;
445                 SlapReply rs = {REP_RESULT};
446                 op->o_callback = &cb;
447                 cb.sc_response = slap_null_cb;
448                 op->o_tag = LDAP_REQ_COMPARE;
449                 op->o_req_dn = ni->ni_pam_group_dn;
450                 op->o_req_ndn = ni->ni_pam_group_dn;
451                 ava.aa_desc = ni->ni_pam_group_ad;
452                 ava.aa_value = dn;
453                 op->orc_ava = &ava;
454                 rc = op->o_bd->be_compare( op, &rs );
455                 if ( rs.sr_err != LDAP_COMPARE_TRUE ) {
456                         authzmsg = grpmsg;
457                         rc = NSLCD_PAM_PERM_DENIED;
458                         goto finish;
459                 }
460         }
461
462         /* We need to check the user's entry for these bits */
463         if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) ||
464                 ni->ni_pam_template_ad ||
465                 ni->ni_pam_min_uid || ni->ni_pam_max_uid ) {
466                 rc = be_entry_get_rw( op, &dn, NULL, NULL, 0, &e );
467                 if (rc != LDAP_SUCCESS) {
468                         rc = NSLCD_PAM_USER_UNKNOWN;
469                         goto finish;
470                 }
471         }
472         if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) {
473                 a = attr_find(e->e_attrs, nssov_pam_host_ad);
474                 if (!a || attr_valfind( a,
475                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
476                         SLAP_MR_VALUE_OF_SYNTAX,
477                         &global_host_bv, NULL, op->o_tmpmemctx )) {
478                         rc = NSLCD_PAM_PERM_DENIED;
479                         authzmsg = hostmsg;
480                         goto finish;
481                 }
482         }
483         if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) {
484                 a = attr_find(e->e_attrs, nssov_pam_svc_ad);
485                 if (!a || attr_valfind( a,
486                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
487                         SLAP_MR_VALUE_OF_SYNTAX,
488                         &svc, NULL, op->o_tmpmemctx )) {
489                         rc = NSLCD_PAM_PERM_DENIED;
490                         authzmsg = svcmsg;
491                         goto finish;
492                 }
493         }
494
495 /* from passwd.c */
496 #define UIDN_KEY        2
497
498         if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) {
499                 int id;
500                 char *tmp;
501                 nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
502                 a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc);
503                 if (!a) {
504                         rc = NSLCD_PAM_PERM_DENIED;
505                         authzmsg = uidmsg;
506                         goto finish;
507                 }
508                 id = (int)strtol(a->a_vals[0].bv_val,&tmp,0);
509                 if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') {
510                         rc = NSLCD_PAM_PERM_DENIED;
511                         authzmsg = uidmsg;
512                         goto finish;
513                 }
514                 if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) ||
515                         (ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) {
516                         rc = NSLCD_PAM_PERM_DENIED;
517                         authzmsg = uidmsg;
518                         goto finish;
519                 }
520         }
521
522         if (ni->ni_pam_template_ad) {
523                 a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
524                 if (a)
525                         uid = a->a_vals[0];
526                 else if (!BER_BVISEMPTY(&ni->ni_pam_template))
527                         uid = ni->ni_pam_template;
528         }
529         rc = NSLCD_PAM_SUCCESS;
530
531 finish:
532         WRITE_INT32(fp,NSLCD_VERSION);
533         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
534         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
535         WRITE_BERVAL(fp,&uid);
536         WRITE_BERVAL(fp,&dn);
537         WRITE_INT32(fp,rc);
538         WRITE_BERVAL(fp,&authzmsg);
539         if (e) {
540                 be_entry_release_r(op, e);
541         }
542         switch (rc) {
543         case NSLCD_PAM_SUCCESS:
544                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): success\n", 0,0,0);
545                 break;
546         case NSLCD_PAM_PERM_DENIED:
547                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(): %s\n",
548                         authzmsg.bv_val ? authzmsg.bv_val : "NULL",0,0);
549                 break;
550         default:
551                 Debug(LDAP_DEBUG_TRACE,
552                         "nssov_pam_authz(): permission denied, rc (%d)\n",
553                         rc, 0, 0);
554         }
555         return 0;
556 }
557
558 static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
559 {
560         struct berval dn, uid, svc, tty, rhost, ruser;
561         int32_t tmpint32;
562         char dnc[1024];
563         char svcc[256];
564         char uidc[32];
565         char ttyc[32];
566         char rhostc[256];
567         char ruserc[32];
568         slap_callback cb = {0};
569         SlapReply rs = {REP_RESULT};
570         char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
571         struct berval timestamp, bv[2], *nbv;
572         time_t stamp;
573         Modifications mod;
574         int rc = 0;
575         int sessionID = -1;
576
577         READ_STRING(fp,uidc);
578         uid.bv_val = uidc;
579         uid.bv_len = tmpint32;
580         READ_STRING(fp,dnc);
581         dn.bv_val = dnc;
582         dn.bv_len = tmpint32;
583         READ_STRING(fp,svcc);
584         svc.bv_val = svcc;
585         svc.bv_len = tmpint32;
586         READ_STRING(fp,ttyc);
587         tty.bv_val = ttyc;
588         tty.bv_len = tmpint32;
589         READ_STRING(fp,rhostc);
590         rhost.bv_val = rhostc;
591         rhost.bv_len = tmpint32;
592         READ_STRING(fp,ruserc);
593         ruser.bv_val = ruserc;
594         ruser.bv_len = tmpint32;
595         READ_INT32(fp,stamp);
596
597         Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n",
598                 action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', dn.bv_val,0);
599
600         if (!dn.bv_len) {
601                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
602                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', "null DN",0);
603                 rc = -1;
604                 goto done;
605         }
606
607         if (!ni->ni_pam_sessions) {
608                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(): %s\n",
609                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
610                         "pam session(s) not configured, ignored",0);
611                 rc = -1;
612                 goto done;
613         }
614
615         {
616                 int i, found=0;
617                 for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) {
618                         if (ni->ni_pam_sessions[i].bv_len != svc.bv_len)
619                                 continue;
620                         if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, svc.bv_val)) {
621                                 found = 1;
622                                 break;
623                         }
624                 }
625                 if (!found) {
626                         Debug(LDAP_DEBUG_TRACE,
627                                 "nssov_pam_sess_%c(): service(%s) not configured, ignored\n",
628                                 action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
629                                 svc.bv_val,0);
630                         rc = -1;
631                         goto done;
632                 }
633         }
634
635         slap_op_time( &op->o_time, &op->o_tincr );
636         timestamp.bv_len = sizeof(timebuf);
637         timestamp.bv_val = timebuf;
638         if (action == NSLCD_ACTION_PAM_SESS_O )
639                 stamp = op->o_time;
640         slap_timestamp( &stamp, &timestamp );
641         bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + svc.bv_len +
642                 tty.bv_len + ruser.bv_len + rhost.bv_len + STRLENOF("    (@)");
643         bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx );
644         sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)",
645                 timestamp.bv_val, global_host_bv.bv_val, svc.bv_val, tty.bv_val,
646                 ruser.bv_val, rhost.bv_val);
647
648         Debug(LDAP_DEBUG_TRACE, "nssov_pam_sess_%c(): loginStatus (%s) \n",
649                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', bv[0].bv_val,0);
650         
651         mod.sml_numvals = 1;
652         mod.sml_values = bv;
653         BER_BVZERO(&bv[1]);
654         attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx );
655         mod.sml_nvalues = nbv;
656         mod.sml_desc = ad_loginStatus;
657         mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD :
658                 LDAP_MOD_DELETE;
659         mod.sml_flags = SLAP_MOD_INTERNAL;
660         mod.sml_next = NULL;
661
662         cb.sc_response = slap_null_cb;
663         op->o_callback = &cb;
664         op->o_tag = LDAP_REQ_MODIFY;
665         op->o_dn = op->o_bd->be_rootdn;
666         op->o_ndn = op->o_bd->be_rootndn;
667         op->orm_modlist = &mod;
668         op->orm_no_opattrs = 1;
669         op->o_req_dn = dn;
670         op->o_req_ndn = dn;
671         if (op->o_bd->be_modify( op, &rs ) != LDAP_SUCCESS) {
672                 Debug(LDAP_DEBUG_TRACE,
673                         "nssov_pam_sess_%c(): modify op failed\n",
674                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
675                         0,0);
676                 rc = -1;
677         }
678
679         if ( mod.sml_next ) {
680                 slap_mods_free( mod.sml_next, 1 );
681         }
682         ber_bvarray_free_x( nbv, op->o_tmpmemctx );
683
684 done:;
685
686         if (rc == 0) {
687                 Debug(LDAP_DEBUG_TRACE,
688                         "nssov_pam_sess_%c(): success\n",
689                         action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c',
690                         0,0);
691                 sessionID = op->o_time;
692         }
693         WRITE_INT32(fp,NSLCD_VERSION);
694         WRITE_INT32(fp,action);
695         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
696         WRITE_INT32(fp,sessionID);
697         return 0;
698 }
699
700 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
701 {
702         return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O);
703 }
704
705 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
706 {
707         return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C);
708 }
709
710 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
711 {
712         struct berval npw;
713         int32_t tmpint32;
714         char dnc[1024];
715         char uidc[32];
716         char opwc[256];
717         char npwc[256];
718         char svcc[256];
719         struct paminfo pi;
720         int rc;
721
722         READ_STRING(fp,uidc);
723         pi.uid.bv_val = uidc;
724         pi.uid.bv_len = tmpint32;
725         READ_STRING(fp,dnc);
726         pi.dn.bv_val = dnc;
727         pi.dn.bv_len = tmpint32;
728         READ_STRING(fp,svcc);
729         pi.svc.bv_val = svcc;
730         pi.svc.bv_len = tmpint32;
731         READ_STRING(fp,opwc);
732         pi.pwd.bv_val = opwc;
733         pi.pwd.bv_len = tmpint32;
734         READ_STRING(fp,npwc);
735         npw.bv_val = npwc;
736         npw.bv_len = tmpint32;
737
738         Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",
739                 pi.dn.bv_val ? pi.dn.bv_val : "NULL",
740                 pi.uid.bv_val ? pi.uid.bv_val : "NULL" ,0);
741
742         BER_BVZERO(&pi.msg);
743         pi.ispwdmgr = 0;
744
745         /* nssov_pam prohibits password mod */
746         if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
747                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(): %s (%s)\n",
748                         "password_prohibit_message",
749                         ni->ni_pam_password_prohibit_message.bv_val,0);
750                 ber_str2bv(ni->ni_pam_password_prohibit_message.bv_val, 0, 0, &pi.msg);
751                 rc = NSLCD_PAM_PERM_DENIED;
752                 goto done;
753         }
754
755         if (BER_BVISEMPTY(&pi.dn)) {
756                 /* should not be here at all, pam_authc() should have returned */
757                 /* error */
758                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
759                         "prelim checking failed", 0, 0);
760                 ber_str2bv("no pwmod requesting dn", 0, 0, &pi.msg);
761                 rc = NSLCD_PAM_PERM_DENIED;
762                 goto done;
763         }
764
765         if (BER_BVISEMPTY(&ni->ni_pam_pwdmgr_dn)) {
766                 Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), %s\n",
767                         "pwdmgr not configured", 0, 0);
768                 ber_str2bv("pwdmgr not configured", 0, 0, &pi.msg);
769                 rc = NSLCD_PAM_PERM_DENIED;
770                 goto done;
771         } else if (!ber_bvcmp(&pi.dn, &ni->ni_pam_pwdmgr_dn)) {
772                 /* root user requesting pwmod, convert uid to dn */
773                 pi.ispwdmgr = 1;
774                 rc = pam_uid2dn(ni, op, &pi);
775                 if (rc) {
776                         ber_str2bv("unable to convert uid to dn", 0, 0, &pi.msg);
777                         rc = NSLCD_PAM_PERM_DENIED;
778                         goto done;
779                 }
780         }
781
782         BerElementBuffer berbuf;
783         BerElement *ber = (BerElement *)&berbuf;
784         struct berval bv;
785         SlapReply rs = {REP_RESULT};
786         slap_callback cb = {0};
787
788         ber_init_w_nullc(ber, LBER_USE_DER);
789         ber_printf(ber, "{");
790         if (!BER_BVISEMPTY(&pi.dn))
791                 ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
792                         &pi.dn);
793         /* supply old pwd only when end-user changing pwd */
794         if (!BER_BVISEMPTY(&pi.pwd) && pi.ispwdmgr == 0)
795                 ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD,
796                         &pi.pwd);
797         if (!BER_BVISEMPTY(&npw))
798                 ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
799                         &npw);
800         ber_printf(ber, "N}");
801         ber_flatten2(ber, &bv, 0);
802         op->o_tag = LDAP_REQ_EXTENDED;
803         op->ore_reqoid = slap_EXOP_MODIFY_PASSWD;
804         op->ore_reqdata = &bv;
805
806         if (pi.ispwdmgr) {
807                 /* root user changing end-user passwords */
808                 op->o_dn = ni->ni_pam_pwdmgr_dn;
809                 op->o_ndn = ni->ni_pam_pwdmgr_dn;
810         } else {
811                 /* end-user self-pwd-mod */
812                 op->o_dn = pi.dn;
813                 op->o_ndn = pi.dn;
814         }
815         op->o_callback = &cb;
816         op->o_conn->c_authz_backend = op->o_bd;
817         cb.sc_response = slap_null_cb;
818         op->o_bd = frontendDB;
819         rc = op->o_bd->be_extended(op, &rs);
820         if (rs.sr_text)
821                 ber_str2bv(rs.sr_text, 0, 0, &pi.msg);
822         if (rc == LDAP_SUCCESS)
823                 rc = NSLCD_PAM_SUCCESS;
824         else
825                 rc = NSLCD_PAM_PERM_DENIED;
826
827 done:;
828         Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(), rc (%d)\n", rc, 0, 0);
829         WRITE_INT32(fp,NSLCD_VERSION);
830         WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
831         WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
832         WRITE_BERVAL(fp,&pi.uid);
833         WRITE_BERVAL(fp,&pi.dn);
834         WRITE_INT32(fp,rc);
835         WRITE_BERVAL(fp,&pi.msg);
836         return 0;
837 }
838
839 int nssov_pam_init()
840 {
841         int code = 0;
842         const char *text;
843         if (!ad_loginStatus)
844                 code = slap_str2ad("loginStatus", &ad_loginStatus, &text);
845
846         return code;
847 }