1 /* pam.c - pam processing routines */
4 * Copyright 2009 by Howard Chu, Symas Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 #include <security/pam_modules.h>
20 static int ppolicy_cid;
27 static int pam_bindcb(
28 Operation *op, SlapReply *rs)
30 struct bindinfo *bi = op->o_callback->sc_private;
31 LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE,
35 ber_int_t expire, grace;
36 LDAPPasswordPolicyError error;
40 int rc = ldap_parse_passwordpolicy_control(ld,ctrl,
41 &expire,&grace,&error);
42 if (rc == LDAP_SUCCESS) {
44 char *unit = "seconds";
57 #if 0 /* Who warns about expiration so far in advance? */
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",
77 bi->authz = PAM_NEW_AUTHTOK_REQD;
78 } else if (error != PP_noError) {
79 ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0,
82 case PP_passwordExpired:
83 /* report this during authz */
84 rs->sr_err = LDAP_SUCCESS;
86 case PP_changeAfterReset:
87 bi->authz = PAM_NEW_AUTHTOK_REQD;
91 ldap_ld_free(ld,0,NULL,NULL);
97 int pam_authc(nssov_info *ni,TFILE *fp,Operation *op)
101 slap_callback cb = {0};
102 SlapReply rs = {REP_RESULT};
106 struct berval uid, svc, pwd, sdn, dn;
110 bi.authz = PAM_SUCCESS;
111 bi.msg.bv_val = pwdc;
114 READ_STRING_BUF2(fp,uidc,sizeof(uidc));
116 uid.bv_len = tmpint32;
117 READ_STRING_BUF2(fp,svcc,sizeof(svcc));
119 svc.bv_len = tmpint32;
120 READ_STRING_BUF2(fp,pwdc,sizeof(pwdc));
122 pwd.bv_len = tmpint32;
124 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",uid.bv_val,0,0);
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;
132 /* Why didn't we make this a berval? */
133 hlen = strlen(global_host);
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);
141 slap_sasl2dn(op, &sdn, &dn, 0);
142 op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx );
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;
151 dnNormalize( 0, NULL, NULL, &sdn, &dn, op->o_tmpmemctx );
155 /* Should only need to do this once at open time, but there's always
156 * the possibility that ppolicy will get loaded later.
159 rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST,
162 /* of course, 0 is a valid cid, but it won't be ppolicy... */
164 op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL;
166 cb.sc_response = pam_bindcb;
168 op->o_callback = &cb;
169 op->o_dn.bv_val[0] = 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;
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.
185 if (rc == LDAP_SUCCESS)
186 send_ldap_result(op, &rs);
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;
194 WRITE_INT32(fp,NSLCD_VERSION);
195 WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
196 WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
198 WRITE_INT32(fp,bi.authz); /* authz */
199 WRITE_BERVAL(fp,&dn);
200 WRITE_BERVAL(fp,&bi.msg); /* authzmsg */
204 int pam_authz(nssov_info *ni,TFILE *fp,Operation *op)
206 struct berval dn, svc;
207 struct berval authzmsg = BER_BVNULL;
208 struct berval tmpluser = BER_BVNULL;
213 READ_STRING_BUF2(fp,dnc,sizeof(dnc));
215 dn.bv_len = tmpint32;
216 READ_STRING_BUF2(fp,svcc,sizeof(svcc));
218 svc.bv_len = tmpint32;
220 Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0);
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);
231 int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op)
233 struct berval dn, svc;
238 READ_STRING_BUF2(fp,dnc,sizeof(dnc));
240 dn.bv_len = tmpint32;
241 READ_STRING_BUF2(fp,svcc,sizeof(svcc));
243 svc.bv_len = tmpint32;
245 Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_o(%s)\n",dn.bv_val,0,0);
247 WRITE_INT32(fp,NSLCD_VERSION);
248 WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O);
249 WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
253 int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op)
255 struct berval dn, svc;
260 READ_STRING_BUF2(fp,dnc,sizeof(dnc));
262 dn.bv_len = tmpint32;
263 READ_STRING_BUF2(fp,svcc,sizeof(svcc));
265 svc.bv_len = tmpint32;
267 Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_c(%s)\n",dn.bv_val,0,0);
269 WRITE_INT32(fp,NSLCD_VERSION);
270 WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C);
271 WRITE_INT32(fp,NSLCD_RESULT_SUCCESS);
275 int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op)
277 struct berval dn, uid, opw, npw;
284 READ_STRING_BUF2(fp,dnc,sizeof(dnc));
286 dn.bv_len = tmpint32;
287 READ_STRING_BUF2(fp,uidc,sizeof(uidc));
289 uid.bv_len = tmpint32;
290 READ_STRING_BUF2(fp,opwc,sizeof(opwc));
292 opw.bv_len = tmpint32;
293 READ_STRING_BUF2(fp,npwc,sizeof(npwc));
295 npw.bv_len = tmpint32;
297 Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n",dn.bv_val,uid.bv_val,0);
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);