8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-26 08:43:03 +01:00
firebird-mirror/src/jrd/pwd.cpp

371 lines
7.9 KiB
C++
Raw Normal View History

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.02 Dmitry Yemanov: Implemented cached security database connection
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
#include <stdlib.h>
#include "../jrd/gds.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
#include "../jrd/pwd.h"
#include "../jrd/enc_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/sch_proto.h"
#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
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
};
/* Transaction parameter buffer */
2001-05-23 15:26:42 +02:00
const UCHAR SecurityDatabase::TPB[4] = {
2001-05-23 15:26:42 +02:00
isc_tpb_version1,
isc_tpb_read,
2001-05-23 15:26:42 +02:00
isc_tpb_concurrency,
isc_tpb_wait
};
/******************************************************************************
2001-05-23 15:26:42 +02:00
*
* Static instance of the database
*/
2001-05-23 15:26:42 +02:00
SecurityDatabase& SecurityDatabase::instance()
{
static SecurityDatabase db;
return db;
2001-05-23 15:26:42 +02:00
}
/******************************************************************************
2001-05-23 15:26:42 +02:00
*
* Private interface
*/
2001-05-23 15:26:42 +02:00
void SecurityDatabase::fini()
{
if (is_cached && counter > 0)
2001-05-23 15:26:42 +02:00
{
if (--counter == 1)
{
counter = 0;
THREAD_EXIT;
isc_detach_database(status, &lookup_db);
THREAD_ENTER;
}
2001-05-23 15:26:42 +02:00
}
}
void SecurityDatabase::init()
{
counter += (is_cached) ? 1 : 0;
}
2001-05-23 15:26:42 +02:00
bool SecurityDatabase::lookup_user(TEXT * user_name, int *uid, int *gid, TEXT * pwd)
2001-05-23 15:26:42 +02: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
/* 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';
strncpy(uname, user_name, 129);
2001-05-23 15:26:42 +02:00
/* Attach database and compile request */
2001-05-23 15:26:42 +02:00
if (!prepare())
2001-05-23 15:26:42 +02: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);
}
/* Lookup */
isc_tr_handle lookup_trans = 0;
2001-05-23 15:26:42 +02: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);
}
if (!isc_start_and_send(status, &lookup_req, &lookup_trans, 0, sizeof(uname), uname, 0))
2001-05-23 15:26:42 +02:00
{
while (1)
2001-05-23 15:26:42 +02: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
}
}
isc_rollback_transaction(status, &lookup_trans);
2001-05-23 15:26:42 +02:00
if (!is_cached)
{
isc_detach_database(status, &lookup_db);
}
2001-05-23 15:26:42 +02:00
THREAD_ENTER;
return notfound;
}
bool SecurityDatabase::prepare()
2001-05-23 15:26:42 +02: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)
{
ihandle->ihndl_object = &lookup_db;
2001-05-23 15:26:42 +02:00
break;
}
}
if (!ihandle)
{
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;
lookup_db = lookup_req = 0;
2001-05-23 15:26:42 +02:00
/* initialize the data base's name */
2001-05-23 15:26:42 +02:00
getPath(user_info_name);
2001-05-23 15:26:42 +02: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;
*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;
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
* understand this combination */
2001-05-23 15:26:42 +02:00
isc_attach_database(status, 0, user_info_name, &lookup_db, 0, 0);
}
2001-05-23 15:26:42 +02:00
assert(ihandle->ihndl_object == &lookup_db);
2001-05-23 15:26:42 +02:00
ihandle->ihndl_object = NULL;
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])
{
return false;
2001-05-23 15:26:42 +02:00
}
return true;
2001-05-23 15:26:42 +02:00
}
/******************************************************************************
*
* Public interface
*/
void SecurityDatabase::getPath(TEXT* path_buffer)
{
gds__prefix(path_buffer, USER_INFO_NAME);
}
2001-05-23 15:26:42 +02:00
void SecurityDatabase::initialize()
{
instance().init();
}
void SecurityDatabase::shutdown()
{
instance().fini();
}
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
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
notfound = instance().lookup_user(name, uid, gid, pw1);
#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;
}