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