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