]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/nssov/pam.c
1ee873b0e47c6504b7c9b291ed23a7e9902b7958
[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
18 #include <security/pam_modules.h>
19
20 static int ppolicy_cid;
21
22 struct bindinfo {
23         int authz;
24         struct berval msg;
25 };
26
27 static int pam_bindcb(
28         Operation *op, SlapReply *rs)
29 {
30         struct bindinfo *bi = op->o_callback->sc_private;
31         LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
32                 rs->sr_ctrls, NULL);
33         if (ctrl) {
34                 LDAP *ld;
35                 ber_int_t expire, grace;
36                 LDAPPasswordPolicyError error;
37
38                 ldap_create(&ld);
39                 if (ld) {
40                         int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
41                                 &expire,&grace,&error);
42                         if (rc == LDAP_SUCCESS) {
43                                 if (expire >= 0) {
44                                         char *unit = "seconds";
45                                         if (expire > 60) {
46                                                 expire /= 60;
47                                                 unit = "minutes";
48                                         }
49                                         if (expire > 60) {
50                                                 expire /= 60;
51                                                 unit = "hours";
52                                         }
53                                         if (expire > 24) {
54                                                 expire /= 24;
55                                                 unit = "days";
56                                         }
57 #if 0   /* Who warns about expiration so far in advance? */
58                                         if (expire > 7) {
59                                                 expire /= 7;
60                                                 unit = "weeks";
61                                         }
62                                         if (expire > 4) {
63                                                 expire /= 4;
64                                                 unit = "months";
65                                         }
66                                         if (expire > 12) {
67                                                 expire /= 12;
68                                                 unit = "years";
69                                         }
70 #endif
71                                         bi->msg.bv_len = sprintf(bi->msg.bv_val,
72                                                 "\nWARNING: Password expires in %d %s\n", expire, unit);
73                                 } else if (grace > 0) {
74                                         bi->msg.bv_len = sprintf(bi->msg.bv_val,
75                                                 "Password expired; %d grace logins remaining",
76                                                 grace);
77                                         bi->authz = PAM_NEW_AUTHTOK_REQD;
78                                 } else if (error != PP_noError) {
79                                         ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
80                                                 &bi->msg);
81                                         switch (error) {
82                                         case PP_passwordExpired:
83                                                 /* report this during authz */
84                                                 rs->sr_err = LDAP_SUCCESS;
85                                                 /* fallthru */
86                                         case PP_changeAfterReset:
87                                                 bi->authz = PAM_NEW_AUTHTOK_REQD;
88                                         }
89                                 }
90                         }
91                         ldap_ld_free(ld,0,NULL,NULL);
92                 }
93         }
94         return LDAP_SUCCESS;
95 }
96
97 int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
98 {
99         int32_t tmpint32;
100         int rc;
101         slap_callback cb = {0};
102         SlapReply rs = {REP_RESULT};
103         char uidc[32];
104         char svcc[256];
105         char pwdc[256];
106         struct berval uid, svc, pwd, sdn, dn;
107         int hlen;
108         struct bindinfo bi;
109
110         bi.authz = PAM_SUCCESS;
111         bi.msg.bv_val = pwdc;
112         bi.msg.bv_len = 0;
113
114         READ_STRING_BUF2(fp,uidc,sizeof(uidc));
115         uid.bv_val = uidc;
116         uid.bv_len = tmpint32;
117         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
118         svc.bv_val = svcc;
119         svc.bv_len = tmpint32;
120         READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
121         pwd.bv_val = pwdc;
122         pwd.bv_len = tmpint32;
123
124         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",uid.bv_val,0,0);
125
126         if (!isvalidusername(&uid)) {
127                 Debug(LDAP_DEBUG_ANY,"nssov_pam_authc(%s): invalid user name\n",uid.bv_val,0,0);
128                 rc = PAM_USER_UNKNOWN;
129                 goto finish;
130         }
131
132         /* Why didn't we make this a berval? */
133         hlen = strlen(global_host);
134
135         /* First try this form, to allow service-dependent mappings */
136         /* cn=<service>+uid=<user>,cn=<host>,cn=pam,cn=auth */
137         sdn.bv_len = uid.bv_len + svc.bv_len + hlen + STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" );
138         sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx );
139         sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth", svcc, uidc, global_host);
140         BER_BVZERO(&dn);
141         slap_sasl2dn(op, &sdn, &dn, 0);
142         op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
143
144         /* If no luck, do a basic uid search */
145         if (BER_BVISEMPTY(&dn)) {
146                 if (!nssov_uid2dn(op, ni, &uid, &dn)) {
147                         rc = PAM_USER_UNKNOWN;
148                         goto finish;
149                 }
150                 sdn = dn;
151                 dnNormalize( 0, NULL, NULL, &sdn, &dn, op->o_tmpmemctx );
152         }
153         BER_BVZERO(&sdn);
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 = &bi;
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 = pwd;
177         op->o_req_dn = dn;
178         op->o_req_ndn = dn;
179         slap_op_time( &op->o_time, &op->o_tincr );
180         rc = op->o_bd->be_bind( op, &rs );
181         memset(pwd.bv_val,0,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 = PAM_SUCCESS; break;
189         case LDAP_INVALID_CREDENTIALS: rc = PAM_AUTH_ERR; break;
190         default: rc = PAM_AUTH_ERR; break;
191         }
192
193 finish:
194         WRITE_INT32(fp,NSLCD_VERSION);
195         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
196         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
197         WRITE_INT32(fp,rc);
198         WRITE_INT32(fp,bi.authz);       /* authz */
199         WRITE_BERVAL(fp,&dn);
200         WRITE_BERVAL(fp,&bi.msg);       /* authzmsg */
201         return 0;
202 }
203
204 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
205 {
206         struct berval dn, svc;
207         struct berval authzmsg = BER_BVNULL;
208         struct berval tmpluser = BER_BVNULL;
209         int32_t tmpint32;
210         char dnc[1024];
211         char svcc[256];
212
213         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
214         dn.bv_val = dnc;
215         dn.bv_len = tmpint32;
216         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
217         svc.bv_val = svcc;
218         svc.bv_len = tmpint32;
219
220         Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0);
221
222         WRITE_INT32(fp,NSLCD_VERSION);
223         WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ);
224         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
225         WRITE_INT32(fp,PAM_SUCCESS);
226         WRITE_BERVAL(fp,&authzmsg);
227         WRITE_BERVAL(fp,&tmpluser);
228         return 0;
229 }
230
231 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
232 {
233         struct berval dn, svc;
234         int32_t tmpint32;
235         char dnc[1024];
236         char svcc[256];
237
238         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
239         dn.bv_val = dnc;
240         dn.bv_len = tmpint32;
241         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
242         svc.bv_val = svcc;
243         svc.bv_len = tmpint32;
244
245         Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_o(%s)\n",dn.bv_val,0,0);
246
247         WRITE_INT32(fp,NSLCD_VERSION);
248         WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O);
249         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
250         return 0;
251 }
252
253 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
254 {
255         struct berval dn, svc;
256         int32_t tmpint32;
257         char dnc[1024];
258         char svcc[256];
259
260         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
261         dn.bv_val = dnc;
262         dn.bv_len = tmpint32;
263         READ_STRING_BUF2(fp,svcc,sizeof(svcc));
264         svc.bv_val = svcc;
265         svc.bv_len = tmpint32;
266
267         Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_c(%s)\n",dn.bv_val,0,0);
268
269         WRITE_INT32(fp,NSLCD_VERSION);
270         WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C);
271         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
272         return 0;
273 }
274
275 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
276 {
277         struct berval dn, uid, opw, npw;
278         int32_t tmpint32;
279         char dnc[1024];
280         char uidc[256];
281         char opwc[256];
282         char npwc[256];
283
284         READ_STRING_BUF2(fp,dnc,sizeof(dnc));
285         dn.bv_val = dnc;
286         dn.bv_len = tmpint32;
287         READ_STRING_BUF2(fp,uidc,sizeof(uidc));
288         uid.bv_val = uidc;
289         uid.bv_len = tmpint32;
290         READ_STRING_BUF2(fp,opwc,sizeof(opwc));
291         opw.bv_val = opwc;
292         opw.bv_len = tmpint32;
293         READ_STRING_BUF2(fp,npwc,sizeof(npwc));
294         npw.bv_val = npwc;
295         npw.bv_len = tmpint32;
296
297         Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",dn.bv_val,uid.bv_val,0);
298
299         BER_BVZERO(&npw);
300         WRITE_INT32(fp,NSLCD_VERSION);
301         WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD);
302         WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
303         WRITE_INT32(fp,PAM_SUCCESS);
304         WRITE_BERVAL(fp,&npw);
305         return 0;
306 }