pw_mgmt.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /* pw_mgmt.c
  13. */
  14. #include <time.h>
  15. #include <string.h>
  16. #include "slap.h"
  17. /****************************************************************************/
  18. /* prototypes */
  19. /****************************************************************************/
  20. /* need_new_pw() is called when non rootdn bind operation succeeds with authentication */
  21. int
  22. need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req )
  23. {
  24. time_t cur_time, pw_exp_date;
  25. Slapi_Mods smods;
  26. double diff_t = 0;
  27. char *cur_time_str = NULL;
  28. char *passwordExpirationTime = NULL;
  29. char *timestring;
  30. char *dn;
  31. const Slapi_DN *sdn;
  32. passwdPolicy *pwpolicy = NULL;
  33. int pwdGraceUserTime = 0;
  34. char graceUserTime[8];
  35. if (NULL == e) {
  36. return (-1);
  37. }
  38. slapi_mods_init (&smods, 0);
  39. sdn = slapi_entry_get_sdn_const( e );
  40. dn = slapi_entry_get_ndn( e );
  41. pwpolicy = new_passwdPolicy(pb, dn);
  42. /* after the user binds with authentication, clear the retry count */
  43. if ( pwpolicy->pw_lockout == 1)
  44. {
  45. if(slapi_entry_attr_get_int( e, "passwordRetryCount") > 0)
  46. {
  47. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordRetryCount", "0");
  48. }
  49. }
  50. cur_time = current_time();
  51. /* get passwordExpirationTime attribute */
  52. passwordExpirationTime= slapi_entry_attr_get_charptr(e, "passwordExpirationTime");
  53. if (passwordExpirationTime == NULL)
  54. {
  55. /* password expiration date is not set.
  56. * This is ok for data that has been loaded via ldif2ldbm
  57. * Set expiration time if needed,
  58. * don't do further checking and return 0 */
  59. if (pwpolicy->pw_exp == 1) {
  60. pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_maxage);
  61. timestring = format_genTime (pw_exp_date);
  62. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
  63. slapi_ch_free_string(&timestring);
  64. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
  65. pw_apply_mods(sdn, &smods);
  66. } else if (pwpolicy->pw_lockout == 1) {
  67. pw_apply_mods(sdn, &smods);
  68. }
  69. slapi_mods_done(&smods);
  70. return ( 0 );
  71. }
  72. pw_exp_date = parse_genTime(passwordExpirationTime);
  73. slapi_ch_free_string(&passwordExpirationTime);
  74. /* Check if password has been reset */
  75. if ( pw_exp_date == NO_TIME ) {
  76. /* check if changing password is required */
  77. if ( pwpolicy->pw_must_change ) {
  78. /* set c_needpw for this connection to be true. this client
  79. now can only change its own password */
  80. pb->pb_conn->c_needpw = 1;
  81. *t=0;
  82. /* We need to include "changeafterreset" error in
  83. * passwordpolicy response control. So, we will not be
  84. * done here. We remember this scenario by (c_needpw=1)
  85. * and check it before sending the control from various
  86. * places. We will also add LDAP_CONTROL_PWEXPIRED control
  87. * as the return value used to be (1).
  88. */
  89. goto skip;
  90. }
  91. /* Mark that first login occured */
  92. pw_exp_date = NOT_FIRST_TIME;
  93. timestring = format_genTime(pw_exp_date);
  94. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
  95. slapi_ch_free_string(&timestring);
  96. }
  97. skip:
  98. /* if password never expires, don't need to go on; return 0 */
  99. if ( pwpolicy->pw_exp == 0 ) {
  100. /* check for "changeafterreset" condition */
  101. if (pb->pb_conn->c_needpw == 1) {
  102. if (pwresponse_req) {
  103. slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET );
  104. }
  105. slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  106. }
  107. pw_apply_mods(sdn, &smods);
  108. slapi_mods_done(&smods);
  109. return ( 0 );
  110. }
  111. /* check if password expired. If so, abort bind. */
  112. cur_time_str = format_genTime ( cur_time );
  113. if ((pw_exp_date != NO_TIME) && (pw_exp_date != NOT_FIRST_TIME) &&
  114. (diff_t = difftime(pw_exp_date, parse_genTime(cur_time_str))) <= 0) {
  115. slapi_ch_free_string(&cur_time_str); /* only need this above */
  116. /* password has expired. Check the value of
  117. * passwordGraceUserTime and compare it
  118. * against the value of passwordGraceLimit */
  119. pwdGraceUserTime = slapi_entry_attr_get_int( e, "passwordGraceUserTime");
  120. if ( pwpolicy->pw_gracelimit > pwdGraceUserTime ) {
  121. pwdGraceUserTime++;
  122. sprintf ( graceUserTime, "%d", pwdGraceUserTime );
  123. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE,
  124. "passwordGraceUserTime", graceUserTime);
  125. pw_apply_mods(sdn, &smods);
  126. slapi_mods_done(&smods);
  127. if (pwresponse_req) {
  128. /* check for "changeafterreset" condition */
  129. if (pb->pb_conn->c_needpw == 1) {
  130. slapi_pwpolicy_make_response_control( pb, -1,
  131. ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
  132. LDAP_PWPOLICY_CHGAFTERRESET);
  133. } else {
  134. slapi_pwpolicy_make_response_control( pb, -1,
  135. ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
  136. -1);
  137. }
  138. }
  139. if (pb->pb_conn->c_needpw == 1) {
  140. slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  141. }
  142. return ( 0 );
  143. }
  144. /* password expired and user exceeded limit of grace attemps.
  145. * Send result and also the control */
  146. slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  147. if (pwresponse_req) {
  148. slapi_pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED );
  149. }
  150. slapi_send_ldap_result ( pb, LDAP_INVALID_CREDENTIALS, NULL,
  151. "password expired!", 0, NULL );
  152. /* abort bind */
  153. /* pass pb to do_unbind(). pb->pb_op->o_opid and
  154. pb->pb_op->o_tag are not right but I don't see
  155. do_unbind() checking for those. We might need to
  156. create a pb for unbind operation. Also do_unbind calls
  157. pre and post ops. Maybe we don't want to call them */
  158. if (pb->pb_conn && (LDAP_VERSION2 == pb->pb_conn->c_ldapversion)) {
  159. /* We close the connection only with LDAPv2 connections */
  160. disconnect_server( pb->pb_conn, pb->pb_op->o_connid,
  161. pb->pb_op->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
  162. }
  163. /* Apply current modifications */
  164. pw_apply_mods(sdn, &smods);
  165. slapi_mods_done(&smods);
  166. return (-1);
  167. }
  168. slapi_ch_free((void **) &cur_time_str );
  169. /* check if password is going to expire within "passwordWarning" */
  170. /* Note that if pw_exp_date is NO_TIME or NOT_FIRST_TIME,
  171. * we must send warning first and this changes the expiration time.
  172. * This is done just below since diff_t is 0
  173. */
  174. if ( diff_t <= pwpolicy->pw_warning ) {
  175. int pw_exp_warned = 0;
  176. pw_exp_warned = slapi_entry_attr_get_int( e, "passwordExpWarned");
  177. if ( !pw_exp_warned ){
  178. /* first time send out a warning */
  179. /* reset the expiration time to current + warning time
  180. * and set passwordExpWarned to true
  181. */
  182. if (pb->pb_conn->c_needpw != 1) {
  183. pw_exp_date = time_plus_sec(cur_time, pwpolicy->pw_warning);
  184. }
  185. timestring = format_genTime(pw_exp_date);
  186. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
  187. slapi_ch_free_string(&timestring);
  188. slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "1");
  189. *t = pwpolicy->pw_warning;
  190. } else {
  191. *t = (long)diff_t; /* jcm: had to cast double to long */
  192. }
  193. pw_apply_mods(sdn, &smods);
  194. slapi_mods_done(&smods);
  195. if (pwresponse_req) {
  196. /* check for "changeafterreset" condition */
  197. if (pb->pb_conn->c_needpw == 1) {
  198. slapi_pwpolicy_make_response_control( pb, *t, -1,
  199. LDAP_PWPOLICY_CHGAFTERRESET);
  200. } else {
  201. slapi_pwpolicy_make_response_control( pb, *t, -1,
  202. -1);
  203. }
  204. }
  205. if (pb->pb_conn->c_needpw == 1) {
  206. slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  207. }
  208. return (2);
  209. } else {
  210. if (pwresponse_req && pwpolicy->pw_send_expiring) {
  211. slapi_pwpolicy_make_response_control( pb, diff_t, -1, -1);
  212. slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, diff_t);
  213. }
  214. }
  215. pw_apply_mods(sdn, &smods);
  216. slapi_mods_done(&smods);
  217. /* Leftover from "changeafterreset" condition */
  218. if (pb->pb_conn->c_needpw == 1) {
  219. slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
  220. }
  221. /* passes checking, return 0 */
  222. return( 0 );
  223. }
  224. /* Called once from main */
  225. void
  226. pw_init ( void )
  227. {
  228. slapdFrontendConfig_t *slapdFrontendConfig;
  229. pw_set_componentID(generate_componentid(NULL, COMPONENT_PWPOLICY));
  230. slapdFrontendConfig = getFrontendConfig();
  231. pw_mod_allowchange_aci (!slapdFrontendConfig->pw_policy.pw_change &&
  232. !slapdFrontendConfig->pw_policy.pw_must_change);
  233. #if defined(USE_OLD_UNHASHED)
  234. slapi_add_internal_attr_syntax( PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
  235. PSEUDO_ATTR_UNHASHEDUSERPASSWORD_OID,
  236. OCTETSTRING_SYNTAX_OID, 0,
  237. /* Clients don't need to directly modify
  238. * PSEUDO_ATTR_UNHASHEDUSERPASSWORD */
  239. SLAPI_ATTR_FLAG_NOUSERMOD|
  240. SLAPI_ATTR_FLAG_NOEXPOSE);
  241. #endif
  242. }