]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/pam.c
50e91adc0e07fee3285142bb9e406dbd0567cea8
[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;
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 || attr_valfind( a,
404                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
405                         SLAP_MR_VALUE_OF_SYNTAX,
406                         &global_host_bv, NULL, op->o_tmpmemctx )) {
407                         rc = NSLCD_PAM_PERM_DENIED;
408                         authzmsg = hostmsg;
409                         goto finish;
410                 }
411         }
412         if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) {
413                 a = attr_find(e->e_attrs, nssov_pam_svc_ad);
414                 if (!a || attr_valfind( a,
415                         SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
416                         SLAP_MR_VALUE_OF_SYNTAX,
417                         &svc, NULL, op->o_tmpmemctx )) {
418                         rc = NSLCD_PAM_PERM_DENIED;
419                         authzmsg = svcmsg;
420                         goto finish;
421                 }
422         }
423
424 /* from passwd.c */
425 #define UIDN_KEY        2
426
427         if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) {
428                 int id;
429                 char *tmp;
430                 nssov_mapinfo *mi = &ni->ni_maps[NM_passwd];
431                 a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc);
432                 if (!a) {
433                         rc = NSLCD_PAM_PERM_DENIED;
434                         authzmsg = uidmsg;
435                         goto finish;
436                 }
437                 id = (int)strtol(a->a_vals[0].bv_val,&tmp,0);
438                 if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') {
439                         rc = NSLCD_PAM_PERM_DENIED;
440                         authzmsg = uidmsg;
441                         goto finish;
442                 }
443                 if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) ||
444                         (ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) {
445                         rc = NSLCD_PAM_PERM_DENIED;
446                         authzmsg = uidmsg;
447                         goto finish;
448                 }
449         }
450
451         if (ni->ni_pam_template_ad) {
452                 a = attr_find(e->e_attrs, ni->ni_pam_template_ad);
453                 if (a)
454                         uid = a->a_vals[0];
455                 else if (!BER_BVISEMPTY(&ni->ni_pam_template))
456                         uid = ni->ni_pam_template;
457         }
458         rc = NSLCD_PAM_SUCCESS;
459
460 finish:
461         WRITE_INT32(fp,NSLCD_VERSION);
462         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
463         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
464         WRITE_BERVAL(fp,&uid);
465         WRITE_BERVAL(fp,&dn);
466         WRITE_INT32(fp,rc);
467         WRITE_BERVAL(fp,&authzmsg);
468         if (e) {
469                 be_entry_release_r(op, e);
470         }
471         return 0;
472 }
473
474 static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action)
475 {
476         struct berval dn, uid, svc, tty, rhost, ruser;
477         int32_t tmpint32;
478         char dnc[1024];
479         char svcc[256];
480         char uidc[32];
481         char ttyc[32];
482         char rhostc[256];
483         char ruserc[32];
484         slap_callback cb = {0};
485         SlapReply rs = {REP_RESULT};
486         char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE];
487         struct berval timestamp, bv[2], *nbv;
488         time_t stamp;
489         Modifications mod;
490
491         READ_STRING_BUF2(fp,uidc,sizeof(uidc));
492         uid.bv_val = uidc;
493         uid.bv_len = tmpint32;
494         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
495         dn.bv_val = dnc;
496         dn.bv_len = tmpint32;
497         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
498         svc.bv_val = svcc;
499         svc.bv_len = tmpint32;
500         READ_STRING_BUF2(fp,ttyc,sizeof(ttyc));
501         tty.bv_val = ttyc;
502         tty.bv_len = tmpint32;
503         READ_STRING_BUF2(fp,rhostc,sizeof(rhostc));
504         rhost.bv_val = rhostc;
505         rhost.bv_len = tmpint32;
506         READ_STRING_BUF2(fp,ruserc,sizeof(ruserc));
507         ruser.bv_val = ruserc;
508         ruser.bv_len = tmpint32;
509         READ_INT32(fp,stamp);
510
511         Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n",
512                 action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', dn.bv_val,0);
513
514         if (!dn.bv_len || !ni->ni_pam_sessions) return 0;
515
516         {
517                 int i, found=0;
518                 for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) {
519                         if (ni->ni_pam_sessions[i].bv_len != svc.bv_len)
520                                 continue;
521                         if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, svc.bv_val)) {
522                                 found = 1;
523                                 break;
524                         }
525                 }
526                 if (!found) return 0;
527         }
528
529         slap_op_time( &op->o_time, &op->o_tincr );
530         timestamp.bv_len = sizeof(timebuf);
531         timestamp.bv_val = timebuf;
532         if (action == NSLCD_ACTION_PAM_SESS_O )
533                 stamp = op->o_time;
534         slap_timestamp( &stamp, &timestamp );
535         bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + svc.bv_len +
536                 tty.bv_len + ruser.bv_len + rhost.bv_len + STRLENOF("    (@)");
537         bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx );
538         sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)",
539                 timestamp.bv_val, global_host_bv.bv_val, svc.bv_val, tty.bv_val,
540                 ruser.bv_val, rhost.bv_val);
541         
542         mod.sml_numvals = 1;
543         mod.sml_values = bv;
544         BER_BVZERO(&bv[1]);
545         attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx );
546         mod.sml_nvalues = nbv;
547         mod.sml_desc = ad_loginStatus;
548         mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD :
549                 LDAP_MOD_DELETE;
550         mod.sml_flags = SLAP_MOD_INTERNAL;
551         mod.sml_next = NULL;
552
553         cb.sc_response = slap_null_cb;
554         op->o_callback = &cb;
555         op->o_tag = LDAP_REQ_MODIFY;
556         op->o_dn = op->o_bd->be_rootdn;
557         op->o_ndn = op->o_bd->be_rootndn;
558         op->orm_modlist = &mod;
559         op->orm_no_opattrs = 1;
560         op->o_req_dn = dn;
561         op->o_req_ndn = dn;
562         op->o_bd->be_modify( op, &rs );
563         if ( mod.sml_next ) {
564                 slap_mods_free( mod.sml_next, 1 );
565         }
566         ber_bvarray_free_x( nbv, op->o_tmpmemctx );
567
568         WRITE_INT32(fp,NSLCD_VERSION);
569         WRITE_INT32(fp,action);
570         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
571         WRITE_INT32(fp,op->o_time);
572         return 0;
573 }
574
575 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
576 {
577         return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O);
578 }
579
580 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
581 {
582         return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C);
583 }
584
585 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
586 {
587         struct berval npw;
588         int32_t tmpint32;
589         char dnc[1024];
590         char uidc[32];
591         char opwc[256];
592         char npwc[256];
593         char svcc[256];
594         struct paminfo pi;
595         int rc;
596
597         READ_STRING_BUF2(fp,uidc,sizeof(uidc));
598         pi.uid.bv_val = uidc;
599         pi.uid.bv_len = tmpint32;
600         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
601         pi.dn.bv_val = dnc;
602         pi.dn.bv_len = tmpint32;
603         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
604         pi.svc.bv_val = svcc;
605         pi.svc.bv_len = tmpint32;
606         READ_STRING_BUF2(fp,opwc,sizeof(opwc));
607         pi.pwd.bv_val = opwc;
608         pi.pwd.bv_len = tmpint32;
609         READ_STRING_BUF2(fp,npwc,sizeof(npwc));
610         npw.bv_val = npwc;
611         npw.bv_len = tmpint32;
612
613         Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",
614                 pi.dn.bv_val,pi.uid.bv_val,0);
615
616         BER_BVZERO(&pi.msg);
617
618         /* This is a prelim check */
619         if (BER_BVISEMPTY(&pi.dn)) {
620                 rc = pam_do_bind(ni,fp,op,&pi);
621                 if (rc == NSLCD_PAM_IGNORE)
622                         rc = NSLCD_PAM_SUCCESS;
623         } else {
624                 BerElementBuffer berbuf;
625                 BerElement *ber = (BerElement *)&berbuf;
626                 struct berval bv;
627                 SlapReply rs = {REP_RESULT};
628                 slap_callback cb = {0};
629
630                 ber_init_w_nullc(ber, LBER_USE_DER);
631                 ber_printf(ber, "{");
632                 if (!BER_BVISEMPTY(&pi.pwd))
633                         ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD,
634                                 &pi.pwd);
635                 if (!BER_BVISEMPTY(&npw))
636                         ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
637                                 &npw);
638                 ber_printf(ber, "N}");
639                 ber_flatten2(ber, &bv, 0);
640                 op->o_tag = LDAP_REQ_EXTENDED;
641                 op->ore_reqoid = slap_EXOP_MODIFY_PASSWD;
642                 op->ore_reqdata = &bv;
643                 op->o_dn = pi.dn;
644                 op->o_ndn = pi.dn;
645                 op->o_callback = &cb;
646                 op->o_conn->c_authz_backend = op->o_bd;
647                 cb.sc_response = slap_null_cb;
648                 op->o_bd = frontendDB;
649                 rc = op->o_bd->be_extended(op, &rs);
650                 if (rs.sr_text)
651                         ber_str2bv(rs.sr_text, 0, 0, &pi.msg);
652                 if (rc == LDAP_SUCCESS)
653                         rc = NSLCD_PAM_SUCCESS;
654                 else
655                         rc = NSLCD_PAM_PERM_DENIED;
656         }
657         WRITE_INT32(fp,NSLCD_VERSION);
658         WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
659         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
660         WRITE_BERVAL(fp,&pi.uid);
661         WRITE_BERVAL(fp,&pi.dn);
662         WRITE_INT32(fp,rc);
663         WRITE_BERVAL(fp,&pi.msg);
664         return 0;
665 }
666
667 int nssov_pam_init()
668 {
669         int code = 0;
670         if (!ad_loginStatus)
671                 code = register_at( at_loginStatus, &ad_loginStatus, 0 );
672         return code;
673 }