2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
|
|
|
* MODULE: pwd.e
|
|
|
|
* DESCRIPTION: User information database access
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Interbase Public
|
|
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy
|
|
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an
|
|
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
|
|
* or implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code was created by Inprise Corporation
|
|
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
|
|
* Copyright (C) Inprise Corporation.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
2003-02-03 14:34:16 +01:00
|
|
|
*
|
|
|
|
* 2003.02.02 Dmitry Yemanov: Implemented cached security database connection
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "../jrd/gds.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
2003-02-13 23:38:04 +01:00
|
|
|
#include "../jrd/jrd_pwd.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/enc_proto.h"
|
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/sch_proto.h"
|
2003-05-02 20:41:12 +02:00
|
|
|
#include "../jrd/thd_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
#ifdef SUPERSERVER
|
|
|
|
const bool SecurityDatabase::is_cached = true;
|
|
|
|
#else
|
|
|
|
const bool SecurityDatabase::is_cached = false;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* BLR to search database for user name record */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
const UCHAR SecurityDatabase::PWD_REQUEST[256] = {
|
2001-05-23 15:26:42 +02:00
|
|
|
blr_version5,
|
|
|
|
blr_begin,
|
|
|
|
blr_message, 1, 4, 0,
|
|
|
|
blr_long, 0,
|
|
|
|
blr_long, 0,
|
|
|
|
blr_short, 0,
|
|
|
|
blr_text, 34, 0,
|
|
|
|
blr_message, 0, 1, 0,
|
|
|
|
blr_cstring, 129, 0,
|
|
|
|
blr_receive, 0,
|
|
|
|
blr_begin,
|
|
|
|
blr_for,
|
|
|
|
blr_rse, 1,
|
|
|
|
blr_relation, 5, 'U', 'S', 'E', 'R', 'S', 0,
|
|
|
|
blr_first,
|
|
|
|
blr_literal, blr_short, 0, 1, 0,
|
|
|
|
blr_boolean,
|
|
|
|
blr_eql,
|
|
|
|
blr_field, 0, 9, 'U', 'S', 'E', 'R', '_', 'N', 'A', 'M', 'E',
|
|
|
|
blr_parameter, 0, 0, 0,
|
|
|
|
blr_end,
|
|
|
|
blr_send, 1,
|
|
|
|
blr_begin,
|
|
|
|
blr_assignment,
|
|
|
|
blr_field, 0, 3, 'G', 'I', 'D',
|
|
|
|
blr_parameter, 1, 0, 0,
|
|
|
|
blr_assignment,
|
|
|
|
blr_field, 0, 3, 'U', 'I', 'D',
|
|
|
|
blr_parameter, 1, 1, 0,
|
|
|
|
blr_assignment,
|
|
|
|
blr_literal, blr_short, 0, 1, 0,
|
|
|
|
blr_parameter, 1, 2, 0,
|
|
|
|
blr_assignment,
|
|
|
|
blr_field, 0, 6, 'P', 'A', 'S', 'S', 'W', 'D',
|
|
|
|
blr_parameter, 1, 3, 0,
|
|
|
|
blr_end,
|
|
|
|
blr_send, 1,
|
|
|
|
blr_assignment,
|
|
|
|
blr_literal, blr_short, 0, 0, 0,
|
|
|
|
blr_parameter, 1, 2, 0,
|
|
|
|
blr_end,
|
|
|
|
blr_end,
|
|
|
|
blr_eoc
|
|
|
|
};
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* Transaction parameter buffer */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
const UCHAR SecurityDatabase::TPB[4] = {
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_tpb_version1,
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_tpb_read,
|
2001-05-23 15:26:42 +02:00
|
|
|
isc_tpb_concurrency,
|
|
|
|
isc_tpb_wait
|
|
|
|
};
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/******************************************************************************
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
2003-02-03 14:34:16 +01:00
|
|
|
* Static instance of the database
|
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
SecurityDatabase& SecurityDatabase::instance()
|
|
|
|
{
|
|
|
|
static SecurityDatabase db;
|
|
|
|
return db;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-05-02 20:41:12 +02:00
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Constructor & destructor
|
|
|
|
*/
|
|
|
|
|
|
|
|
SecurityDatabase::SecurityDatabase()
|
|
|
|
: lookup_db(0), lookup_req(0), counter(0)
|
|
|
|
{
|
|
|
|
THD_MUTEX_INIT(&mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
SecurityDatabase::~SecurityDatabase()
|
|
|
|
{
|
|
|
|
THD_MUTEX_DESTROY(&mutex);
|
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/******************************************************************************
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
2003-02-03 14:34:16 +01:00
|
|
|
* Private interface
|
|
|
|
*/
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-05-02 20:41:12 +02:00
|
|
|
void SecurityDatabase::lock()
|
|
|
|
{
|
|
|
|
THD_MUTEX_LOCK(&mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SecurityDatabase::unlock()
|
|
|
|
{
|
|
|
|
THD_MUTEX_UNLOCK(&mutex);
|
|
|
|
}
|
|
|
|
|
2003-05-07 09:06:42 +02:00
|
|
|
void SecurityDatabase::fini()
|
2003-02-03 14:34:16 +01:00
|
|
|
{
|
2003-05-02 20:41:12 +02:00
|
|
|
#ifndef EMBEDDED
|
2003-05-07 09:06:42 +02:00
|
|
|
if (is_cached && counter > 0)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-05-07 09:06:42 +02:00
|
|
|
if (--counter == 1)
|
2003-02-03 16:01:41 +01:00
|
|
|
{
|
|
|
|
counter = 0;
|
|
|
|
THREAD_EXIT;
|
|
|
|
isc_detach_database(status, &lookup_db);
|
|
|
|
THREAD_ENTER;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-05-02 20:41:12 +02:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
void SecurityDatabase::init()
|
|
|
|
{
|
|
|
|
counter += (is_cached) ? 1 : 0;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
bool SecurityDatabase::lookup_user(TEXT * user_name, int *uid, int *gid, TEXT * pwd)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
bool notfound = true; // user found flag
|
|
|
|
TEXT uname[129]; // user name buffer
|
|
|
|
user_record user; // user record
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* Start by clearing the output data */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (uid)
|
|
|
|
*uid = 0;
|
|
|
|
if (gid)
|
|
|
|
*gid = 0;
|
|
|
|
if (pwd)
|
|
|
|
*pwd = '\0';
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
strncpy(uname, user_name, 129);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* Attach database and compile request */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
if (!prepare())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
if (lookup_db)
|
|
|
|
{
|
|
|
|
isc_detach_database(status, &lookup_db);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
THREAD_ENTER;
|
|
|
|
ERR_post(gds_psw_attach, 0);
|
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* Lookup */
|
|
|
|
|
|
|
|
isc_tr_handle lookup_trans = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
if (isc_start_transaction(status, &lookup_trans, 1, &lookup_db, sizeof(TPB), TPB))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
THREAD_ENTER;
|
|
|
|
ERR_post(gds_psw_start_trans, 0);
|
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
if (!isc_start_and_send(status, &lookup_req, &lookup_trans, 0, sizeof(uname), uname, 0))
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
while (1)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_receive(status, &lookup_req, 1, sizeof(user), &user, 0);
|
|
|
|
if (!user.flag || status[1])
|
|
|
|
break;
|
|
|
|
notfound = false;
|
|
|
|
if (uid)
|
|
|
|
*uid = user.uid;
|
|
|
|
if (gid)
|
|
|
|
*gid = user.gid;
|
|
|
|
if (pwd)
|
|
|
|
strncpy(pwd, user.password, 32);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_rollback_transaction(status, &lookup_trans);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
if (!is_cached)
|
|
|
|
{
|
|
|
|
isc_detach_database(status, &lookup_db);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
THREAD_ENTER;
|
|
|
|
|
|
|
|
return notfound;
|
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
bool SecurityDatabase::prepare()
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
TEXT user_info_name[MAXPATHLEN];
|
|
|
|
IHNDL ihandle;
|
|
|
|
SCHAR* dpb;
|
|
|
|
SCHAR dpb_buffer[256];
|
|
|
|
SSHORT dpb_len;
|
|
|
|
|
|
|
|
/* dimitr: access to the class members in this routine should be synchronized
|
|
|
|
when fine grained locking will be implemented for the SS architecture */
|
|
|
|
|
|
|
|
if (counter > 1)
|
|
|
|
{
|
|
|
|
THREAD_EXIT;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Register as internal database handle */
|
|
|
|
|
|
|
|
for (ihandle = internal_db_handles; ihandle; ihandle = ihandle->ihndl_next)
|
|
|
|
{
|
|
|
|
if (ihandle->ihndl_object == NULL)
|
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
ihandle->ihndl_object = &lookup_db;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ihandle)
|
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
ihandle = (IHNDL) gds__alloc ((SLONG) sizeof(struct ihndl));
|
|
|
|
ihandle->ihndl_object = &lookup_db;
|
2001-05-23 15:26:42 +02:00
|
|
|
ihandle->ihndl_next = internal_db_handles;
|
|
|
|
internal_db_handles = ihandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
THREAD_EXIT;
|
|
|
|
|
2003-02-03 16:01:41 +01:00
|
|
|
lookup_db = lookup_req = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* initialize the data base's name */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
getPath(user_info_name);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/* Perhaps build up a dpb */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
dpb = dpb_buffer;
|
|
|
|
|
|
|
|
*dpb++ = gds_dpb_version1;
|
|
|
|
|
|
|
|
// insert username
|
|
|
|
static const char szAuthenticator[] = "authenticator";
|
|
|
|
const size_t nAuthNameLen = strlen(szAuthenticator);
|
|
|
|
*dpb++ = gds_dpb_user_name;
|
|
|
|
*dpb++ = nAuthNameLen;
|
|
|
|
memcpy(dpb, szAuthenticator, nAuthNameLen);
|
|
|
|
dpb += nAuthNameLen;
|
|
|
|
|
|
|
|
// insert password
|
|
|
|
static const char szPassword[] = "none";
|
|
|
|
const size_t nPswdLen = strlen(szPassword);
|
|
|
|
*dpb++ = gds_dpb_password;
|
|
|
|
*dpb++ = nPswdLen;
|
|
|
|
memcpy(dpb, szPassword, nPswdLen);
|
|
|
|
dpb += nPswdLen;
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
*dpb++ = isc_dpb_sec_attach; // Attachment is for the security database
|
|
|
|
*dpb++ = 1; // Parameter value length
|
|
|
|
*dpb++ = TRUE; // Parameter value
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
dpb_len = dpb - dpb_buffer;
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_attach_database(status, 0, user_info_name, &lookup_db, dpb_len, dpb_buffer);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (status[1] == gds_login)
|
|
|
|
{
|
|
|
|
/* we may be going against a V3 database which does not
|
2003-02-03 14:34:16 +01:00
|
|
|
* understand this combination */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_attach_database(status, 0, user_info_name, &lookup_db, 0, 0);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 16:01:41 +01:00
|
|
|
assert(ihandle->ihndl_object == &lookup_db);
|
2001-05-23 15:26:42 +02:00
|
|
|
ihandle->ihndl_object = NULL;
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
isc_compile_request(status, &lookup_db, &lookup_req, sizeof(PWD_REQUEST),
|
|
|
|
reinterpret_cast<char*>(const_cast<UCHAR*>(PWD_REQUEST)));
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
if (status[1])
|
|
|
|
{
|
2003-02-03 14:34:16 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
/******************************************************************************
|
|
|
|
*
|
|
|
|
* Public interface
|
|
|
|
*/
|
|
|
|
|
|
|
|
void SecurityDatabase::getPath(TEXT* path_buffer)
|
|
|
|
{
|
|
|
|
gds__prefix(path_buffer, USER_INFO_NAME);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
void SecurityDatabase::initialize()
|
|
|
|
{
|
|
|
|
instance().init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SecurityDatabase::shutdown()
|
|
|
|
{
|
2003-05-07 09:06:42 +02:00
|
|
|
instance().fini();
|
2003-02-03 14:34:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void SecurityDatabase::verifyUser(TEXT* name,
|
|
|
|
TEXT* user_name,
|
|
|
|
TEXT* password,
|
|
|
|
TEXT* password_enc,
|
|
|
|
int* uid,
|
|
|
|
int* gid,
|
|
|
|
int* node_id)
|
|
|
|
{
|
|
|
|
bool notfound;
|
|
|
|
TEXT *p, *q, pw1[33], pw2[33], pwt[33];
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-03 14:34:16 +01:00
|
|
|
if (user_name)
|
|
|
|
{
|
|
|
|
for (p = name, q = user_name; *q; q++, p++)
|
|
|
|
{
|
|
|
|
*p = UPPER7(*q);
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Look up the user name in the userinfo database and use the parameters
|
|
|
|
found there. This means that another database must be accessed, and
|
|
|
|
that means the current context must be saved and restored. */
|
|
|
|
|
|
|
|
#ifdef EMBEDDED
|
|
|
|
return;
|
|
|
|
#else
|
2003-05-02 20:41:12 +02:00
|
|
|
THREAD_EXIT;
|
|
|
|
instance().lock();
|
|
|
|
THREAD_ENTER;
|
2003-02-03 14:34:16 +01:00
|
|
|
notfound = instance().lookup_user(name, uid, gid, pw1);
|
2003-05-02 20:41:12 +02:00
|
|
|
instance().unlock();
|
2003-02-03 14:34:16 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Punt if the user has specified neither a raw nor an encrypted password,
|
|
|
|
or if the user has specified both a raw and an encrypted password,
|
|
|
|
or if the user name specified was not in the password database
|
|
|
|
(or if there was no password database - it's still not found) */
|
|
|
|
|
|
|
|
if ((!password && !password_enc) ||
|
|
|
|
(password && password_enc) ||
|
|
|
|
notfound)
|
|
|
|
{
|
|
|
|
ERR_post(gds_login, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (password) {
|
|
|
|
strcpy(pwt, ENC_crypt(password, PASSWORD_SALT));
|
|
|
|
password_enc = pwt + 2;
|
|
|
|
}
|
|
|
|
strcpy(pw2, ENC_crypt(password_enc, PASSWORD_SALT));
|
|
|
|
if (strncmp(pw1, pw2 + 2, 11)) {
|
|
|
|
ERR_post(gds_login, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
*node_id = 0;
|
|
|
|
}
|