CREATE TABLE USERS (
USER_NAME VARCHAR(128),
PASSWD VARCHAR(32) );
GRANT SELECT ON USERS TO PUBLIC;
GRANT UPDATE(PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME)
ON USERS
TO PUBLIC;
This modification (as well as original isc4.gdb)
has still drawback that full list of users and their encrypted passwords
is visible to PUBLIC. (And thus it is easier to download list of other users/passwords
and try to break them locally by brute force.)
CREATE TABLE USERS2 (
USER_NAME VARCHAR(128),
PASSWD VARCHAR(32) );
CREATE VIEW USERS AS
SELECT *
FROM USERS2
WHERE USER = ''
OR USER = 'SYSDBA'
OR USER = USER_NAME;
GRANT SELECT
ON USERS
TO PUBLIC;
GRANT UPDATE(PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME)
ON USERS
TO PUBLIC;
USER = USER_NAMEensures that each user sees its own record. The condition
USER = 'SYSDBA'ensures that SYSDBA can see all records. The condition
USER = ''is important because USER variable contains empty string during password verification!
SELECT PASSWD
FROM USERS
WHERE USER_NAME=:usr;
In other words, we can have some kind of select-trigger, or login-trigger.
Such procedure can then be used e.g. to refuse login during some part of day,
or to log date/time when user tried to login. Note that it is not possible
to distinguish whether login was successful, and that it logs only known usernames
(i.e. names already stored in USERS table). But even this limited information
can be useful, e.g. to see whether somebody logged at unusual time (night),
or to reveal suspicious number of logins during short time.
To implement this we need
CREATE TABLE log_table
EXTERNAL FILE 'C:\Program Files\Borland\InterBase\isc4.log'
( tstamp TIMESTAMP,
uname CHAR(31) );
If you want log table to be readable as text file, you can add two more fields:
one CHAR(1) to separate tstamp and uname fields,
one CHAR(2) to be filled with CR+LF codes by stored procedure,
and use CHAR(20) instead of TIMESTAMP.
SUSPEND is called) to indicate success, or does not return
any row (i.e. EXIT is called) to indicate that row is forbidden.
Output parameter is just formal, it's value is ignored.
CREATE PROCEDURE log_proc
(un VARCHAR(31))
RETURNS
(x CHAR(1))
AS
BEGIN
IF (USER='')
THEN
INSERT INTO log_table (TSTAMP, UNAME)
VALUES ( CURRENT_TIMESTAMP, :un);
IF (USER='' OR USER='SYSDBA' OR USER=:un)
THEN
SUSPEND;
END
Notice the test (USER=''); when IB server verifies password,
USER variable is empty! It helps distinguish whether password
is being verified by IB server, or whether user is directly connected to isc4.gdb.
CREATE VIEW USERS (USER_NAME) AS
SELECT *
FROM users2
WHERE EXISTS (SELECT * FROM log_proc(users2.user_name));
GRANT SELECT ON USERS TO PUBLIC;
GRANT UPDATE(PASSWD, GROUP_NAME, UID, GID, FIRST_NAME, MIDDLE_NAME, LAST_NAME)
ON USERS
TO PUBLIC;
GRANT INSERT ON log_table TO PROCEDURE log_proc;
GRANT EXECUTE ON PROCEDURE log_proc TO PUBLIC;
Because log entires are constantly appended to log_table,
it is necessary from time to time to delete or rename the external file!
After the user name/password is verified, the security database (and thus external file as well)
is disconnected/released by the server, so renaming the file should not be problem.
DECLARE VARIABLE cnt INTEGER;
SELECT COUNT(*)
FROM log_table
WHERE uname=:un
AND tstamp>CURRENT_TIMESTAMP-0.0007
INTO :cnt;
IF (cnt>=3) THEN EXIT;
RDB$USERS, but users have access to it via view USERS only.
Users can now change their own passwords by default.
There is built in protection against brute force attack - after a few unsuccessfull
attempts to login, the user and IP address will be locked for few seconds.
Although it is not possible to directly connect to security database,
it is possible to make backup of it using Services API.
C:\Program Files\Firebird\security.fdb = C:\Program Files\Firebird\My_Security_Db.fdb(Server restart is not necessary when changing
aliases.conf.)
ExternalFileAccess = Fullor
ExternalFileAccess = Restrict dir1;dir2;...(But this change is not important for modified security database because of limitation imposed by Read Only transaction.)
ADMIN_DB "new_name_of_admin_database"
External files are now allowed in "ext" subdirectory only, or in directories specified in "ibconfig" file by
EXTERNAL_FILE_DIRECTORY "/ext"