Description:
------------
When using the Oracle OCI8 client from PHP 4.3.10 on Windows:
OCILogon:
When a user's password expires, and they enter their grace period, OCILogon no longer returns a valid connection. PHP returns false and sends a warning message when OCILogon is called in this situation.
A warning that their password has expired should be available, and the connection should also available for full use.
The underlying OCI client returns a status of OCI_SUCCESS_WITH_INFO in this situation, and sets the error message to "ORA-28002: the password will expire within %d days". _oci_open_session() only checks if the return value of OCISessionBegin() is OCI_SUCCESS. OCI_SUCCESS_WITH_INFO should also be checked for.
OCIPasswordChange:
After the grace period has expired, the application should still be able to use OCIPasswordChange (as used in SQL+), without a valid connection, to change a user's password. This is the only action allowed at this point.
The Oracle docs state that OCIPasswordChange can be used without a valid connection (when mode=OCI_AUTH), and that it will create a connection after successfully changing the password.
--- From Oracle docs:--------------------------------------
OCIPasswordChange()
Purpose
This call allows the password of an account to be changed.
Syntax
sword OCIPasswordChange ( OCISvcCtx *svchp,
OCIError *errhp,
CONST text *user_name,
ub4 usernm_len,
CONST text *opasswd,
ub4 opasswd_len,
CONST text *npasswd,
sb4 npasswd_len,
ub4 mode );
Parameters
svchp (IN/OUT)
A handle to a service context. The service context handle must be initialized and have a server context handle associated with it.
errhp (IN)
An error handle you can pass to OCIErrorGet() for diagnostic information in the event of an error.
user_name (IN)
Specifies the user name. It points to a character string, whose length is specified in usernm_len. This parameter must be NULL if the service context has been initialized with an user session handle.
usernm_len (IN)
The length of the user name string specified in user_name. For a valid user name string, usernm_len must be non-zero.
opasswd (IN)
Specifies the user's old password. It points to a character string, whose length is specified in opasswd_len.
opasswd_len (IN)
The length of the old password string specified in opasswd. For a valid password string, opasswd_len must be non-zero.
npasswd (IN)
Specifies the user's new password. It points to a character string, whose length is specified in npasswd_len which must be non-zero for a valid password string. If the password complexity verification routine is specified in the user's profile to verify the new password's complexity, the new password must meet the complexity requirements of the verification function.
npasswd_len (IN)
Then length of the new password string specified in npasswd. For a valid password string, npasswd_len must be non-zero.
mode (IN)
Can be OCI_DEFAULT and/or OCI_AUTH. If set to OCI_AUTH, the following happens:
* If a user session context is not created, this call creates the user session context and changes the password. At the end of the call, the user session context is not cleared. Hence the user remains logged in.
If the user session context is already created, this call just changes the password and the flag has no effect on the session. Hence the user still remains logged in.
Comments
This call allows the password of an account to be changed. This call is similar to OCISessionBegin() with the following differences:
* If the user session is already established, it authenticates the account using the old password and then changes the password to the new password
* If the user session is not established, it establishes a user session and authenticates the account using the old password, then changes the password to the new password.
This call is useful when the password of an account has expired and OCISessionBegin() returns an error (ORA-28001) or warning that indicates that the password has expired.
Related Functions
OCISessionBegin()
---End From Oracle docs -----------------------------------
Reproduce code:
---------------
In SQL+:
create profile test_profile limit password_life_time 0.001 password_grace_time 0.001;
create user bob identified by password profile test_profile;
login as "bob" and run this query to see when the password will expire:
select to_char(EXPIRY_DATE, 'YYYY-MM-DD HH24:MI:SS') E_DATE, EXPIRY_DATE - SYSDATE DIFF from SYS.USER_USERS;
<?php
ociinternaldebug(1);
$connection = OCILogon('bob', 'password', 'YOUR_SID');
if (!$connection) {
echo "Database failed to respond. ".var_export(OCIError(), true);
} else {
echo 'OK';
}
?>
Expected result:
----------------
----- During grace period:
Warning: ocilogon(): OCISessionBegin: OCI_SUCCESS_WITH_INFO: ORA-28002: the password will expire within 0 days in ...
OK
----- After grace period:
Warning: ocilogon(): OCISessionBegin: ORA-28001: the password has expired in ...
Database failed to respond. array ( 'code' => 28001, 'message' => 'ORA-28001: the password has expired ', 'offset' => 0, 'sqltext' => '', )
Actual result:
--------------
----- During grace period:
Warning: ocilogon(): OCISessionBegin: OCI_SUCCESS_WITH_INFO: ORA-28002: the password will expire within 0 days in ...
Database failed to respond. array ( 'code' => 28001, 'message' => 'ORA-28002: the password will expire within 0 days ', 'offset' => 0, 'sqltext' => '', )
----- After grace period:
Warning: ocilogon(): OCISessionBegin: ORA-28001: the password has expired in ...
Database failed to respond. array ( 'code' => 28001, 'message' => 'ORA-28001: the password has expired ', 'offset' => 0, 'sqltext' => '', )

This bug has been fixed in CVS.
Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
Thank you for the report, and for helping us make PHP better.