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