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