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