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

368 lines
7.7 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
2003-12-31 06:36:12 +01:00
* MODULE: pwd.cpp
2001-05-23 15:26:42 +02:00
* 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>
2003-11-08 17:40:17 +01:00
#include "../jrd/y_ref.h"
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
#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"
#include "../jrd/thd_proto.h"
2001-05-23 15:26:42 +02:00
#ifdef SUPERSERVER
const bool SecurityDatabase::is_cached = true;
#else
const bool SecurityDatabase::is_cached = false;
#endif
2003-10-05 12:27:08 +02:00
// 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
};
2003-10-05 12:27:08 +02:00
// 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
};
2003-10-05 12:27:08 +02:00
// Static instance of the database
2003-10-03 14:28:54 +02:00
SecurityDatabase SecurityDatabase::instance;
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()
{
2003-10-03 14:28:54 +02:00
counter -= (is_cached) ? 1 : 0;
#ifndef EMBEDDED
2003-10-03 14:28:54 +02:00
if (counter == 1 && lookup_db)
2001-05-23 15:26:42 +02:00
{
2003-10-03 14:28:54 +02:00
THREAD_EXIT;
isc_detach_database(status, &lookup_db);
THREAD_ENTER;
2001-05-23 15:26:42 +02:00
}
#endif
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
{
2003-10-03 14:28:54 +02:00
bool found = false; // user found flag
TEXT uname[129]; // user name buffer
user_record user; // user record
2001-05-23 15:26:42 +02:00
2003-10-05 12:27:08 +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
2003-10-05 12:27:08 +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;
2003-11-08 17:40:17 +01:00
ERR_post(isc_psw_attach, 0);
2001-05-23 15:26:42 +02:00
}
2003-10-05 12:27:08 +02:00
// 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;
2003-11-08 17:40:17 +01:00
ERR_post(isc_psw_start_trans, 0);
2001-05-23 15:26:42 +02:00
}
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;
2003-10-03 14:28:54 +02:00
found = true;
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;
2003-10-03 14:28:54 +02:00
return found;
2001-05-23 15:26:42 +02:00
}
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;
2003-10-03 14:28:54 +02:00
if (lookup_db)
{
THREAD_EXIT;
return true;
}
2003-10-05 12:27:08 +02:00
// Register as internal database handle
2001-05-23 15:26:42 +02:00
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
2003-10-05 12:27:08 +02:00
// Initialize the database name
2001-05-23 15:26:42 +02:00
getPath(user_info_name);
2001-05-23 15:26:42 +02:00
2003-10-05 12:27:08 +02:00
// Perhaps build up a dpb
2001-05-23 15:26:42 +02:00
dpb = dpb_buffer;
2003-11-08 17:40:17 +01:00
*dpb++ = isc_dpb_version1;
2001-05-23 15:26:42 +02:00
2003-10-05 12:27:08 +02:00
// Insert username
2001-05-23 15:26:42 +02:00
static const char szAuthenticator[] = "authenticator";
const size_t nAuthNameLen = strlen(szAuthenticator);
2003-11-08 17:40:17 +01:00
*dpb++ = isc_dpb_user_name;
2001-05-23 15:26:42 +02:00
*dpb++ = nAuthNameLen;
memcpy(dpb, szAuthenticator, nAuthNameLen);
dpb += nAuthNameLen;
2003-10-05 12:27:08 +02:00
// Insert password
2001-05-23 15:26:42 +02:00
static const char szPassword[] = "none";
const size_t nPswdLen = strlen(szPassword);
2003-11-08 17:40:17 +01:00
*dpb++ = isc_dpb_password;
2001-05-23 15:26:42 +02:00
*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
2003-11-08 17:40:17 +01:00
if (status[1] == isc_login)
2001-05-23 15:26:42 +02:00
{
2003-10-05 12:27:08 +02:00
// 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
2003-11-04 00:59:24 +01:00
fb_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<const char*>(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()
{
2003-10-03 14:28:54 +02:00
instance.init();
}
void SecurityDatabase::shutdown()
{
2003-10-03 14:28:54 +02:00
instance.fini();
}
void SecurityDatabase::verifyUser(TEXT* name,
2003-12-31 06:36:12 +01:00
const TEXT* user_name,
const TEXT* password,
const TEXT* password_enc,
int* uid,
int* gid,
int* node_id)
{
if (user_name)
{
2003-10-08 10:42:48 +02:00
TEXT* p = name;
for (const TEXT* q = user_name; *q; ++q, ++p)
{
*p = UPPER7(*q);
}
*p = 0;
}
2003-10-05 12:27:08 +02:00
#ifndef EMBEDDED
// 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.
THREAD_EXIT;
2003-10-05 12:27:08 +02:00
instance.mutex.aquire();
THREAD_ENTER;
2003-10-08 10:42:48 +02:00
TEXT pw1[33];
2003-10-05 12:27:08 +02:00
bool found = instance.lookup_user(name, uid, gid, pw1);
instance.mutex.release();
2003-10-05 12:27:08 +02:00
// 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)
2003-10-03 14:28:54 +02:00
if ((!password && !password_enc) || (password && password_enc) || !found)
{
2003-11-08 17:40:17 +01:00
ERR_post(isc_login, 0);
}
2003-10-08 10:42:48 +02:00
TEXT pwt[33];
if (password) {
strcpy(pwt, ENC_crypt(password, PASSWORD_SALT));
password_enc = pwt + 2;
}
2003-10-08 10:42:48 +02:00
TEXT pw2[33];
strcpy(pw2, ENC_crypt(password_enc, PASSWORD_SALT));
if (strncmp(pw1, pw2 + 2, 11)) {
2003-11-08 17:40:17 +01:00
ERR_post(isc_login, 0);
}
2003-10-05 12:27:08 +02:00
#endif
*node_id = 0;
}