8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 02:03:03 +01:00
firebird-mirror/src/jrd/isc.cpp
2003-03-23 16:50:54 +00:00

1721 lines
38 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: isc.c
* DESCRIPTION: General purpose but non-user routines.
*
* 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): ______________________________________.
*
* Added TCP_NO_DELAY option for superserver on Linux
* FSG 16.03.2001
* Solaris x86 changes - Konstantin Kuznetsov, Neil McCalden
* 26-Sept-2001 Paul Beach - External File Directory Config. Parameter
* 17-Oct-2001 Mike Nordell: CPU affinity
* 01-Feb-2002 Paul Reeves: Removed hard-coded registry path
*
* 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
* 2002.10.30 Sean Leyne - Removed support for obsolete "PC_PLATFORM" define
* 2002.10.30 Sean Leyne - Code Cleanup, removed obsolete "SUN3_3" port
*
*/
/*
$Id: isc.cpp,v 1.30 2003-03-23 16:50:52 alexpeshkoff Exp $
*/
#ifdef DARWIN
#define _STLP_CCTYPE
#endif
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "../jrd/common.h"
#include "gen/codes.h"
#include "../jrd/isc.h"
#include "../jrd/y_ref.h"
#include "../jrd/ibase.h"
#include "../jrd/jrd.h"
#include "../jrd/scl.h"
#include "../jrd/flu_proto.h"
#include "../jrd/gds_proto.h"
#include "../jrd/isc_proto.h"
#include "../jrd/jrd_proto.h"
/* Initialize the structure that hold all the config information */
static struct cfgtbl ISC_def_cfg_tbl[] = {
{ISCCFG_LOCKMEM, ISCCFG_LOCKMEM_KEY, ISCCFG_LOCKMEM_DEF, ISCCFG_LOCKMEM_DEF},
{ISCCFG_LOCKSEM, ISCCFG_LOCKSEM_KEY, ISCCFG_LOCKSEM_DEF, ISCCFG_LOCKSEM_DEF},
{ISCCFG_LOCKSIG, ISCCFG_LOCKSIG_KEY, ISCCFG_LOCKSIG_DEF, ISCCFG_LOCKSIG_DEF},
{ISCCFG_EVNTMEM, ISCCFG_EVNTMEM_KEY, ISCCFG_EVNTMEM_DEF, ISCCFG_EVNTMEM_DEF},
{ISCCFG_DBCACHE, ISCCFG_DBCACHE_KEY, ISCCFG_DBCACHE_DEF, ISCCFG_DBCACHE_DEF},
{ISCCFG_PRIORITY, ISCCFG_PRIORITY_KEY, ISCCFG_PRIORITY_DEF, ISCCFG_PRIORITY_DEF},
{ISCCFG_IPCMAP, ISCCFG_IPCMAP_KEY, ISCCFG_IPCMAP_DEF, ISCCFG_IPCMAP_DEF},
{ISCCFG_MEMMIN, ISCCFG_MEMMIN_KEY, ISCCFG_MEMMIN_DEF, ISCCFG_MEMMIN_DEF},
{ISCCFG_MEMMAX, ISCCFG_MEMMAX_KEY, ISCCFG_MEMMAX_DEF, ISCCFG_MEMMAX_DEF},
{ISCCFG_LOCKORDER, ISCCFG_LOCKORDER_KEY, ISCCFG_LOCKORDER_DEF, ISCCFG_LOCKORDER_DEF},
{ISCCFG_ANYLOCKMEM, ISCCFG_ANYLOCKMEM_KEY, ISCCFG_ANYLOCKMEM_DEF, ISCCFG_ANYLOCKMEM_DEF},
{ISCCFG_ANYLOCKSEM, ISCCFG_ANYLOCKSEM_KEY, ISCCFG_ANYLOCKSEM_DEF, ISCCFG_ANYLOCKSEM_DEF},
{ISCCFG_ANYLOCKSIG, ISCCFG_ANYLOCKSIG_KEY, ISCCFG_ANYLOCKSIG_DEF, ISCCFG_ANYLOCKSIG_DEF},
{ISCCFG_ANYEVNTMEM, ISCCFG_ANYEVNTMEM_KEY, ISCCFG_ANYEVNTMEM_DEF, ISCCFG_ANYEVNTMEM_DEF},
{ISCCFG_LOCKHASH, ISCCFG_LOCKHASH_KEY, ISCCFG_LOCKHASH_DEF, ISCCFG_LOCKHASH_DEF},
{ISCCFG_DEADLOCK, ISCCFG_DEADLOCK_KEY, ISCCFG_DEADLOCK_DEF, ISCCFG_DEADLOCK_DEF},
{ISCCFG_LOCKSPIN, ISCCFG_LOCKSPIN_KEY, ISCCFG_LOCKSPIN_DEF, ISCCFG_LOCKSPIN_DEF},
{ISCCFG_CONN_TIMEOUT, ISCCFG_CONN_TIMEOUT_KEY, ISCCFG_CONN_TIMEOUT_DEF, ISCCFG_CONN_TIMEOUT_DEF},
{ISCCFG_DUMMY_INTRVL, ISCCFG_DUMMY_INTRVL_KEY, ISCCFG_DUMMY_INTRVL_DEF, ISCCFG_DUMMY_INTRVL_DEF},
{ISCCFG_TRACE_POOLS, ISCCFG_TRACE_POOLS_KEY, ISCCFG_TRACE_POOLS_DEF, ISCCFG_TRACE_POOLS_DEF},
{ISCCFG_REMOTE_BUFFER, ISCCFG_REMOTE_BUFFER_KEY, ISCCFG_REMOTE_BUFFER_DEF, ISCCFG_REMOTE_BUFFER_DEF},
#ifdef SET_TCP_NO_DELAY
{ISCCFG_NO_NAGLE, ISCCFG_NO_NAGLE_KEY, ISCCFG_NO_NAGLE_DEF, ISCCFG_NO_NAGLE_DEF},
#endif
#ifdef WIN_NT
{ISCCFG_CPU_AFFINITY_TAG, ISCCFG_CPU_AFFINITY_KEY, ISCCFG_CPU_AFFINITY_DEF, ISCCFG_CPU_AFFINITY_DEF},
#endif
{NULL, 0, 0, 0}
};
static struct cfgtbl *ISC_cfg_tbl = NULL;
/* Temporary file management specific stuff */
#include "../jrd/fil.h"
#include "../jrd/dls_proto.h"
static BOOLEAN dls_init = FALSE;
static BOOLEAN dls_flag = FALSE;
static BOOLEAN fdls_init = FALSE;
#ifdef SUPERSERVER
static BOOLEAN fdls_flag = FALSE;
#endif
/* End of temporary file management specific stuff */
#ifdef SOLARIS
#include <sys/utsname.h>
#endif
#ifdef SCO_EV
#include <sys/utsname.h>
#endif
/* Win32 specific stuff */
#ifdef WIN_NT
#include <windows.h>
static USHORT os_type;
static SECURITY_ATTRIBUTES security_attr;
//static TEXT interbase_directory[MAXPATHLEN];
static BOOLEAN check_user_privilege();
#endif // WIN_NT
static TEXT user_name[256];
static USHORT ast_count;
/* VMS Specific Stuff */
#ifdef VMS
#include <rms.h>
#include <descrip.h>
#include <ssdef.h>
#include <jpidef.h>
#include <prvdef.h>
#include <secdef.h>
#include <lckdef.h>
#include "../jrd/lnmdef.h"
#include "../jrd/prv_m_bypass.h"
#define LOGICAL_NAME_TABLE "LNM$FILE_DEV"
#define WAKE_LOCK "gds__process_%d"
static POKE pokes;
static LKSB wake_lock;
#endif /* of ifdef VMS */
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
/* Unix specific stuff */
#if defined(UNIX)
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif
#ifndef O_RDWR
#include <fcntl.h>
#endif
void isc_internal_set_config_value(UCHAR, ULONG*, ULONG*);
#ifdef VMS
static void blocking_ast(void);
static void poke_ast(POKE);
static int wait_test(SSHORT *);
#endif
#ifndef MAXHOSTLEN
#define MAXHOSTLEN 64
#endif
#ifndef FOPEN_READ_TYPE
#define FOPEN_READ_TYPE "r"
#define FOPEN_WRITE_TYPE "w"
#endif
#ifdef SHLIB_DEFS
#define strchr (*_libgds_strchr)
#define geteuid (*_libgds_geteuid)
#define getpwuid (*_libgds_getpwuid)
#define _ctype (*_libgds__ctype)
#define readlink (*_libgds_readlink)
#define gethostname (*_libgds_gethostname)
#define endpwent (*_libgds_endpwent)
#define getegid (*_libgds_getegid)
extern SCHAR *strchr();
extern uid_t geteuid();
extern struct passwd *getpwuid();
extern SCHAR _ctype[];
extern int readlink();
extern void gethostname();
extern void endpwent();
extern gid_t getegid();
#endif
#ifndef REQUESTER
void DLL_EXPORT ISC_ast_enter(void)
{
/**************************************
*
* I S C _ a s t _ e n t e r
*
**************************************
*
* Functional description
* Enter ast mode.
*
**************************************/
++ast_count;
}
#endif
#ifndef REQUESTER
void DLL_EXPORT ISC_ast_exit(void)
{
/**************************************
*
* I S C _ a s t _ e x i t
*
**************************************
*
* Functional description
* Enter ast mode.
*
**************************************/
--ast_count;
}
#endif
int DLL_EXPORT ISC_check_process_existence(SLONG pid,
SLONG xl_pid,
USHORT super_user)
{
/**************************************
*
* I S C _ c h e c k _ p r o c e s s _ e x i s t e n c e
*
**************************************
*
* Functional description
* Return TRUE if the indicated process
* exists. FALSE otherwise.
*
**************************************/
#if defined(UNIX)
#define CHECK_EXIST
return (kill((int) pid, 0) == -1 &&
(errno == ESRCH
|| (super_user && errno == EPERM)) ? FALSE : TRUE);
#endif
#ifdef VMS
#define CHECK_EXIST
ULONG item;
item = JPI$_PID;
return (lib$getjpi(&item, &pid, NULL, NULL, NULL, NULL) == SS$_NONEXPR) ?
FALSE : TRUE;
#endif
#ifdef WIN_NT
HANDLE handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, (DWORD) pid);
if (!handle && GetLastError() != ERROR_ACCESS_DENIED)
{
return FALSE;
}
CloseHandle(handle);
#endif
#ifndef CHECK_EXIST
return TRUE;
#else
#undef CHECK_EXIST
#endif
}
#ifdef VMS
int ISC_expand_logical_once(
TEXT * file_name,
USHORT file_length, TEXT * expanded_name)
{
/**************************************
*
* I S C _ e x p a n d _ l o g i c a l _ o n c e
*
**************************************
*
* Functional description
* Expand a logical name. If it doesn't exist, return 0.
*
**************************************/
int attr;
USHORT l;
TEXT *p;
ITM items[2];
struct dsc$descriptor_s desc1, desc2;
if (!file_length)
file_length = strlen(file_name);
ISC_make_desc(file_name, &desc1, file_length);
ISC_make_desc(LOGICAL_NAME_TABLE, &desc2, sizeof(LOGICAL_NAME_TABLE) - 1);
items[0].itm_length = 256;
items[0].itm_code = LNM$_STRING;
items[0].itm_buffer = expanded_name;
items[0].itm_return_length = &l;
items[1].itm_length = 0;
items[1].itm_code = 0;
attr = LNM$M_CASE_BLIND;
if (!(sys$trnlnm(&attr, &desc2, &desc1, NULL, items) & 1)) {
while (file_length--)
*expanded_name++ = *file_name++;
*expanded_name = 0;
return 0;
}
expanded_name[l] = 0;
return l;
}
#endif
void DLL_EXPORT ISC_get_config(TEXT * config_file, IPCCFG config_table)
{
/*************************************
*
* I S C _ g e t _ c o n f i g
*
*************************************
*
* Functional description
* Read user-defined values for shared memory and
* semaphores, and temporary directory list
* from a configuration file.
*
************************************/
IPCCFG h;
struct cfgtbl *tbl;
if (ISC_cfg_tbl == NULL) {
IB_FILE *fd;
TEXT *p, *q, buf[80];
TEXT buffer[MAXPATHLEN];
#ifdef SUPERSERVER
int n;
TEXT dir_name[MAXPATHLEN];
ULONG size;
#endif
gds__prefix(buffer, config_file);
config_file = buffer;
/* Read the configuration file into a local buffer. This
local buffer knows about all valid configuration options.
Later requests for configuration information will read it
from the in-memory copy rather than the disk copy */
ISC_cfg_tbl = ISC_def_cfg_tbl;
if ( (fd = ib_fopen(config_file, FOPEN_READ_TYPE)) )
{
while ( (p = ib_fgets(buf, sizeof(buf), fd)) )
{
/* The same keyword can be used more than once for
temp directory definition hence it should be handled
in its own way */
if (strncmp(buf, ISCCFG_TMPDIR, sizeof(ISCCFG_TMPDIR) - 1) == 0)
{
#ifdef SUPERSERVER
/* Note that this should be #ifdef SERVER once we implement that flag.
* We want this code to execute in classic servers as well as superserver,
* but not in client libraries, or in tools which link with a private
* copy of our object file, such as alice and dudley.
* This needs to be changed in time for the first Classic port of V6.0
*/
/* there is temp. directory definition */
if (!dls_init)
if ((n = sscanf(buf + sizeof(ISCCFG_TMPDIR) - 1,
" %ld \"%[^\"]", &size,
dir_name)) == 2)
{
if (DLS_add_dir(size, dir_name))
dls_flag = TRUE;
else {
gds__log
("Unable to use config parameter %s : No memory ",
ISCCFG_TMPDIR);
dls_flag = FALSE;
}
}
#endif
continue;
}
/* The external function directory keyword can also be used
more than once, so handle it separately. */
if (0 == strncmp(buf, ISCCFG_EXT_FUNC_DIR,
sizeof(ISCCFG_EXT_FUNC_DIR) - 1))
{
#ifdef SUPERSERVER
/* Note that this should be #ifdef SERVER once we implement that flag.
* We want this code to execute in classic servers as well as superserver,
* but not in client libraries, or in tools which link with a private
* copy of our object file, such as alice and dudley.
* This needs to be changed in time for the first Classic port of V6.0
*/
/* There is external function directory definition */
if (!fdls_init)
if (1 == sscanf(buf + sizeof(ISCCFG_EXT_FUNC_DIR) - 1,
" \"%[^\"]", dir_name))
{
if (DLS_add_func_dir(dir_name))
fdls_flag = TRUE;
else
{
gds__log
("Unable to use config parameter %s : No memory ",
ISCCFG_EXT_FUNC_DIR);
fdls_flag = FALSE;
}
}
#endif
continue;
}
for (tbl = ISC_cfg_tbl; (q = tbl->cfgtbl_keyword) ; tbl++)
{
p = buf;
/* Scan until we see the end of the keyword or
a mismatch */
while (*q && (*p == *q))
{
p++;
q++;
};
/* If we reached the end of the keyword we've got
a match! The remainder of the input line had
better be spaces and numbers */
if (!*q && (isspace(*p) || isdigit(*p))) {
tbl->cfgtbl_value = atol(p);
break;
}
} /* for */
} /* while */
ib_fclose(fd);
} /* if ib_fopen */
else
{
/* Error opening file. Log a message only if file exists */
if (errno != ENOENT)
gds__log("Unable to open config file \"%s\": errno = %d",
config_file, errno);
}
#ifndef SUPERCLIENT
if (!dls_flag)
{
/* Temp. directory configuration has not been defined.
Let's make default configuration */
if (!(q = getenv("INTERBASE_TMP")) &&
!(q = getenv("TMP")) &&
!(q = getenv("TEMP")))
{
q = WORKDIR;
}
if (!DLS_add_dir(ALLROOM, q))
{
/* we are out of memory, also we can only get here during
server start hence let us exit with an exit status indicating
to the guardian that the server need not be restarted */
gds__log
("Unable to set configuration parameters : No Memory");
exit(STARTUP_ERROR);
}
dls_flag = TRUE;
}
#endif
dls_init = TRUE; /* Temp dir config should be read only once */
fdls_init = TRUE; /* Ext func dir config should be read only once. */
} /* if ICS_cfg_tbl == NULL */
/* The master configuration options are in memory, now for
this request for option values mark each one as not found
and search the memory table for each one. */
if (!config_table) return;
for (h = config_table; h->ipccfg_keyword; h++)
{
h->ipccfg_found = FALSE;
}
for (h = config_table; h->ipccfg_keyword; h++)
{
if (!h->ipccfg_parent_offset ||
!h[h->ipccfg_parent_offset].ipccfg_found)
{
for (tbl = ISC_cfg_tbl; tbl->cfgtbl_keyword; tbl++)
{
if (!strcmp(tbl->cfgtbl_keyword, h->ipccfg_keyword))
{
*h->ipccfg_variable = tbl->cfgtbl_value;
h->ipccfg_key = tbl->cfgtbl_key;
h->ipccfg_found = TRUE;
break;
}
}
}
}
}
#ifndef SUPERCLIENT
int DLL_EXPORT ISC_set_config(TEXT * config_file, IPCCFG config_table)
{
/*************************************
*
* I S C _ s e t _ c o n f i g
*
*************************************
*
* Functional description
* Set new values in the configuration file
* and make them take affect if possible.
*
************************************/
IB_FILE *fd = NULL;
IPCCFG h;
struct cfgtbl *t;
TEXT buffer[MAXPATHLEN];
int ret = 1;
if (config_file)
{
gds__prefix(buffer, config_file);
config_file = buffer;
fd = ib_fopen(config_file, FOPEN_WRITE_TYPE);
}
if ((ISC_cfg_tbl != NULL) && (!config_file || fd))
{
ULONG config_mask = 0;
ret = 0;
/* If config_table = NULL then assume we want to restore defaults,
* otherwise get the users values and use them.
*/
for (t = ISC_def_cfg_tbl; t->cfgtbl_keyword; t++)
{
if (config_table)
{
for (h = config_table; h->ipccfg_variable; h++)
{
if (h->ipccfg_keyword ?
!strcmp(t->cfgtbl_keyword, h->ipccfg_keyword) :
h->ipccfg_key == t->cfgtbl_key)
{
config_mask |= (1 << t->cfgtbl_key);
t->cfgtbl_value = *h->ipccfg_variable;
break;
}
}
}
else if (t->cfgtbl_value != t->cfgtbl_def_value)
{
config_mask |= (1 << t->cfgtbl_key);
t->cfgtbl_value = t->cfgtbl_def_value;
}
}
/* if one of the working set sizes has been set the make sure they're
* both set.
*/
if (config_mask &
((1 << ISCCFG_MEMMIN_KEY) | (1 << ISCCFG_MEMMAX_KEY))) config_mask
|= ((1 << ISCCFG_MEMMIN_KEY) | (1 << ISCCFG_MEMMAX_KEY));
for (t = ISC_def_cfg_tbl; config_mask && t->cfgtbl_keyword; t++)
{
#ifdef SUPERSERVER
if (config_mask & (1 << t->cfgtbl_key))
{
ULONG *valptr = 0;
switch (t->cfgtbl_key)
{
case ISCCFG_MEMMIN_KEY:
valptr = &(t->cfgtbl_value);
break;
case ISCCFG_MEMMAX_KEY:
isc_internal_set_config_value( t->cfgtbl_key,
valptr,
&(t->cfgtbl_value));
break;
default:
isc_internal_set_config_value( t->cfgtbl_key,
&(t->cfgtbl_value),
NULL);
break;
}
}
#endif /* SUPERSERVER */
if (fd)
{
char *p, *q, buf[80];
int tabs;
p = buf;
if (t->cfgtbl_value == t->cfgtbl_def_value)
*p++ = '#';
q = t->cfgtbl_keyword;
while (*q)
*p++ = *q++;
tabs = 4 - (p - buf) / 8;
while (tabs--)
*p++ = '\t';
*p = '\0';
if (ib_fprintf(fd, "%s%ld\n", buf, t->cfgtbl_value) < 0)
gds__log("Error writing config file \"%s\" : errno = %d",
config_file, errno);
}
}
if (fd) {
ib_fclose(fd);
gds__log("Config file \"%s\" has been modified.", config_file);
}
}
return ret;
}
#endif /* ! SUPERCLIENT */
#if (defined SOLARIS || defined SCO_EV)
#define GET_HOST
TEXT *INTERNAL_API_ROUTINE ISC_get_host(TEXT * string, USHORT length)
{
/**************************************
*
* I S C _ g e t _ h o s t ( S O L A R I S )
*
**************************************
*
* Functional description
* Get host name.
*
**************************************/
struct utsname name;
if (uname(&name) >= 0)
strncpy(string, name.nodename, length);
else
strcpy(string, "local");
return string;
}
#endif
#ifdef VMS
#define GET_HOST
TEXT *INTERNAL_API_ROUTINE ISC_get_host(TEXT * string, USHORT length)
{
/**************************************
*
* I S C _ g e t _ h o s t ( V M S )
*
**************************************
*
* Functional description
* Get host name.
*
**************************************/
TEXT *p;
if (!ISC_expand_logical_once("SYS$NODE", sizeof("SYS$NODE") - 1, string))
strcpy(string, "local");
else {
p = string;
if (*p == '_')
++p;
for (; *p && *p != ':'; p++)
if (*p >= 'A' && *p <= 'Z')
*p = *p - 'A' + 'a';
*p = 0;
}
return string;
}
#endif
#ifdef WIN_NT
#define GET_HOST
TEXT *INTERNAL_API_ROUTINE ISC_get_host(TEXT * string, USHORT length)
{
/**************************************
*
* I S C _ g e t _ h o s t ( W I N _ N T )
*
**************************************
*
* Functional description
* Get host name.
* Note that this is not the DNS (TCP/IP) hostname,
* it's the Win32 computer name.
*
**************************************/
DWORD host_len = length;
if (GetComputerName(string, &host_len))
{
string[host_len] = 0;
}
else
{
strcpy(string, "local");
}
return string;
}
#endif
#ifndef GET_HOST
TEXT *INTERNAL_API_ROUTINE ISC_get_host(TEXT * string, USHORT length)
{
/**************************************
*
* I S C _ g e t _ h o s t ( G E N E R I C )
*
**************************************
*
* Functional description
* Get host name.
*
**************************************/
gethostname(string, length);
return string;
}
#endif
#ifdef UNIX
int INTERNAL_API_ROUTINE ISC_get_user(TEXT* name,
int* id,
int* group,
TEXT* project,
TEXT* organization,
int* node,
TEXT* user_string)
{
/**************************************
*
* I S C _ g e t _ u s e r ( U N I X )
*
**************************************
*
* Functional description
* Find out who the user is.
*
**************************************/
/* egid and euid need to be signed, uid_t is unsigned on SUN! */
SLONG egid, euid;
TEXT *p, *q, user_name[256];
struct passwd *passwd;
if (user_string && *user_string) {
for (p = user_name, q = user_string; (*p = *q++) && *p != '.'; p++);
*p = 0;
p = user_name;
egid = euid = -1;
if (*q) {
egid = atoi(q);
while (*q && (*q != '.'))
q++;
if (*q == '.') {
q++;
euid = atoi(q);
}
}
}
else {
euid = (SLONG) geteuid();
egid = (SLONG) getegid();
passwd = getpwuid(euid);
if (passwd)
p = passwd->pw_name;
else
p = "";
endpwent();
}
if (name)
strcpy(name, p);
if (id)
*id = euid;
if (group)
*group = egid;
if (project)
*project = 0;
if (organization)
*organization = 0;
if (node)
*node = 0;
return (euid == 0);
}
#endif
#ifdef VMS
int INTERNAL_API_ROUTINE ISC_get_user(
TEXT * name,
int *id,
int *group,
TEXT * project,
TEXT * organization, int *node, TEXT * user_string)
{
/**************************************
*
* I S C _ g e t _ u s e r ( V M S )
*
**************************************
*
* Functional description
* Find out who the user is.
*
**************************************/
SLONG status, privileges[2];
USHORT uic[2], len0, len1, len2;
TEXT *p, *q, *end, user_name[256];
ITM items[4];
if (user_string && *user_string) {
for (p = user_name, q = user_string; (*p = *q++) && *p != '.'; p++);
*p = 0;
p = user_name;
uic[0] = uic[1] = -1;
if (*q) {
uic[1] = atoi(q);
while (*q && (*q != '.'))
q++;
if (*q == '.') {
q++;
uic[0] = atoi(q);
}
}
privileges[0] = 0;
if (name) {
for (p = user_name; *p && *p != ' ';)
*name++ = *p++;
*name = 0;
}
}
else {
items[0].itm_code = JPI$_UIC;
items[0].itm_length = sizeof(uic);
items[0].itm_buffer = uic;
items[0].itm_return_length = &len0;
items[1].itm_code = JPI$_USERNAME;
items[1].itm_length = sizeof(user_name);
items[1].itm_buffer = user_name;
items[1].itm_return_length = &len1;
items[2].itm_code = JPI$_CURPRIV;
items[2].itm_length = sizeof(privileges);
items[2].itm_buffer = privileges;
items[2].itm_return_length = &len2;
items[3].itm_code = 0;
items[3].itm_length = 0;
status = sys$getjpiw(NULL, NULL, NULL, items, NULL, NULL, NULL);
if (!(status & 1)) {
len1 = 0;
uic[0] = uic[1] = 0;
}
user_name[len1] = 0;
if (name) {
for (p = user_name; *p && *p != ' ';)
*name++ = *p++;
*name = 0;
}
}
if (id)
*id = uic[0];
if (group)
*group = uic[1];
if (project)
*project = 0;
if (organization)
*organization = 0;
if (node)
*node = 0;
return (privileges[0] & (SLONG) PRV$M_BYPASS);
}
#endif
#ifdef WIN_NT
int INTERNAL_API_ROUTINE ISC_get_user(TEXT* name,
int* id,
int* group,
TEXT* project,
TEXT* organization,
int* node,
TEXT* user_string)
{
/**************************************
*
* I S C _ g e t _ u s e r ( W I N _ N T )
*
**************************************
*
* Functional description
* Find out who the user is.
*
**************************************/
if (id)
*id = -1;
if (group)
*group = -1;
if (project)
*project = 0;
if (organization)
*organization = 0;
if (node)
*node = 0;
if (name)
{
name[0] = 0;
DWORD name_len = 128;
if (GetUserName(name, &name_len))
{
name[name_len] = 0;
/* NT user name is case insensitive */
for (DWORD i = 0; i < name_len; i++)
{
name[i] = UPPER7(name[i]);
}
/* This check is not internationalized, the security model needs to be
* reengineered, especially on SUPERSERVER where none of these local
* user (in process) assumptions are valid.
*/
if (!strcmp(name, "ADMINISTRATOR"))
{
if (id)
*id = 0;
if (group)
*group = 0;
}
}
}
return check_user_privilege();
}
//____________________________________________________________
//
// Check to see if the user belongs to the administrator group.
//
// This routine was adapted from code in routine RunningAsAdminstrator
// in \mstools\samples\regmpad\regdb.c.
//
static BOOLEAN check_user_privilege(void)
{
HANDLE tkhandle;
SID_IDENTIFIER_AUTHORITY system_sid_authority = SECURITY_NT_AUTHORITY;
// First we must open a handle to the access token for this thread.
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &tkhandle))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
// If the thread does not have an access token, we'll examine the
// access token associated with the process.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkhandle))
{
CloseHandle(tkhandle);
return FALSE;
}
}
else
{
return FALSE;
}
}
TOKEN_GROUPS* ptg = NULL;
DWORD token_len = 0;
while (TRUE)
{
/* Then we must query the size of the group information associated with
the token. This is guarenteed to fail the first time through
because there is no buffer. */
if (GetTokenInformation(tkhandle,
TokenGroups,
ptg,
token_len,
&token_len))
{
break;
}
/* If there had been a buffer, it's either too small or something
else is wrong. Either way, we can dispose of it. */
if (ptg)
{
gds__free(ptg);
}
/* Here we verify that GetTokenInformation failed for lack of a large
enough buffer. */
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
CloseHandle(tkhandle);
return FALSE;
}
// Allocate a buffer for the group information.
ptg = (TOKEN_GROUPS *) gds__alloc((SLONG) token_len);
if (!ptg)
{
CloseHandle(tkhandle);
return FALSE; /* NOMEM: */
}
// FREE: earlier in this loop, and at procedure return
}
// Create a System Identifier for the Admin group.
PSID admin_sid;
if (!AllocateAndInitializeSid(&system_sid_authority, 2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &admin_sid))
{
gds__free(ptg);
CloseHandle(tkhandle);
return FALSE;
}
// Finally we'll iterate through the list of groups for this access
// token looking for a match against the SID we created above.
BOOLEAN admin_priv = FALSE;
for (DWORD i = 0; i < ptg->GroupCount; i++)
{
if (EqualSid(ptg->Groups[i].Sid, admin_sid))
{
admin_priv = TRUE;
break;
}
}
// Deallocate the SID we created.
FreeSid(admin_sid);
gds__free(ptg);
CloseHandle(tkhandle);
return admin_priv;
}
#endif
#ifdef VMS
int ISC_make_desc(TEXT * string, struct dsc$descriptor *desc, USHORT length)
{
/**************************************
*
* I S C _ m a k e _ d e s c
*
**************************************
*
* Functional description
* Make a VMS string descriptor out of a string. Return
* length of string.
*
**************************************/
desc->dsc$b_dtype = DSC$K_DTYPE_T;
desc->dsc$b_class = DSC$K_CLASS_S;
desc->dsc$a_pointer = string;
if (length)
desc->dsc$w_length = length;
else {
desc->dsc$w_length = 0;
while (*string++)
++desc->dsc$w_length;
}
return desc->dsc$w_length;
}
#endif
SLONG API_ROUTINE ISC_get_prefix(TEXT * passed_string)
{
/**************************************
*
* i s c _ g e t _ p r e f i x
*
**************************************
*
* Functional description
* Parse the 'H' argument further for 'HL' 'HM' or 'H'
*
**************************************/
char c = *passed_string;
int arg_type;
switch (UPPER(c)) {
case '\0':
arg_type = IB_PREFIX_TYPE;
break;
case 'L':
arg_type = IB_PREFIX_LOCK_TYPE;
++passed_string;
break;
case 'M':
arg_type = IB_PREFIX_MSG_TYPE;
++passed_string;
break;
default:
return (-1);
break;
}
return (gds__get_prefix(arg_type, ++passed_string));
}
void API_ROUTINE ISC_prefix(TEXT * string, TEXT * root)
{
/**************************************
*
* i s c _ $ p r e f i x
*
**************************************
*
* Functional description
* Wrapper function for gds__prefix.
*
**************************************/
gds__prefix(string, root);
return;
}
void API_ROUTINE ISC_prefix_lock(TEXT * string, TEXT * root)
{
/**************************************
*
* i s c _ $ p r e f i x _ l o c k
*
**************************************
*
* Functional description
* Wrapper function for gds__prefix_lock.
*
**************************************/
gds__prefix_lock(string, root);
return;
}
void API_ROUTINE ISC_prefix_msg(TEXT * string, TEXT * root)
{
/**************************************
*
* i s c _ $ p r e f i x _ m s g
*
**************************************
*
* Functional description
* Wrapper function for gds__prefix_msg.
*
**************************************/
gds__prefix_msg(string, root);
return;
}
#ifndef REQUESTER
void ISC_set_user(TEXT * string)
{
/**************************************
*
* I S C _ s e t _ u s e r
*
**************************************
*
* Functional description
* Set user name for feeble operating system that don't
* support the concept, or support it badly.
*
**************************************/
strcpy(user_name, string);
}
#endif
#ifdef VMS
void ISC_wait(SSHORT * iosb, SLONG event_flag)
{
/**************************************
*
* I S C _ w a i t ( V M S )
*
**************************************
*
* Functional description
* Wait for a asynchronous VMS event.
*
**************************************/
if (*iosb)
return;
/* If we're at AST state, and we're not running under
a AST invoked thread, wait locally. */
if (ast_count && !gds__ast_active()) {
sys$synch(event_flag, iosb);
return;
}
gds__thread_wait(wait_test, iosb);
}
#endif
#ifdef VMS
void ISC_wake(SLONG process_id)
{
/**************************************
*
* I S C _ w a k e
*
**************************************
*
* Functional description
* Wake up another VMS process. Process can be local or
* remote (but on the same CPU).
*
**************************************/
int status;
POKE poke;
TEXT string[32];
struct dsc$descriptor_s desc;
/* Try to do a simple wake. If this succeeds, we're done. */
status = sys$wake(&process_id, 0);
#ifdef __ALPHA
THREAD_wakeup();
#endif
if (status & 1)
return;
/* Do wake by siezing a lock, delivering a blocking ast */
/* Find a free poke block to use */
for (poke = pokes; poke; poke = poke->poke_next)
if (!poke->poke_use_count)
break;
if (!poke) {
poke = (POKE) gds__alloc((SLONG) sizeof(struct poke));
/* FREE: apparently never freed */
if (!poke) { /* NOMEM: */
DEV_REPORT("ISC_wake: out of memory condition");
return; /* error handling too difficult here */
}
poke->poke_next = pokes;
pokes = poke;
}
++poke->poke_use_count;
sprintf(string, WAKE_LOCK, process_id);
ISC_make_desc(string, &desc, 0);
status = sys$enq(0, /* event flag */
LCK$K_PWMODE, /* lock mode */
&poke->poke_lksb, /* Lock status block */
LCK$M_SYSTEM, /* flags */
&desc, /* resource name */
0, /* parent id */
poke_ast, /* ast address */
poke, /* ast argument */
0, /* blocking ast */
0, /* access mode */
0);
}
#endif
#ifdef VMS
void ISC_wake_init(void)
{
/**************************************
*
* I S C _ w a k e _ i n i t
*
**************************************
*
* Functional description
* Set up to be awakened by another process thru a blocking AST.
*
**************************************/
int status;
TEXT string[32];
FPTR_INT master;
struct dsc$descriptor_s desc;
/* If we already have lock, we're done */
if (wake_lock.lksb_lock_id)
return;
sprintf(string, WAKE_LOCK, getpid());
ISC_make_desc(string, &desc, 0);
status = sys$enqw(0, /* event flag */
LCK$K_PWMODE, /* lock mode */
&wake_lock, /* Lock status block */
LCK$M_SYSTEM, /* flags */
&desc, /* resource name */
0, /* parent id */
0, /* ast address */
0, /* ast argument */
blocking_ast, /* blocking ast */
0, /* access mode */
0);
}
#endif
#ifdef VMS
static void blocking_ast(void)
{
/**************************************
*
* b l o c k i n g _ a s t
*
**************************************
*
* Functional description
* Somebody else is trying to post a lock.
*
**************************************/
int status;
/* Initially down grade the lock to let the other guy complete */
status = sys$enqw(0, /* event flag */
LCK$K_NLMODE, /* lock mode */
&wake_lock, /* Lock status block */
LCK$M_CONVERT, /* flags */
0, /* resource name */
0, /* parent id */
0, /* ast address */
0, /* ast argument */
0, /* blocking ast */
0, /* access mode */
0);
/* Wake us up */
status = sys$wake(0, 0);
/* Now try to upgrade lock */
status = sys$enq(0, /* event flag */
LCK$K_PRMODE, /* lock mode */
&wake_lock, /* Lock status block */
LCK$M_CONVERT, /* flags */
0, /* resource name */
0, /* parent id */
0, /* ast address */
0, /* ast argument */
blocking_ast, /* blocking ast */
0, /* access mode */
0);
}
#endif
#ifdef VMS
static void poke_ast(POKE poke)
{
/**************************************
*
* p o k e _ a s t
*
**************************************
*
* Functional description
* Lock to poke event has completed. Update value block
* and deque the lock.
*
**************************************/
int status;
LKSB *lksb;
lksb = &poke->poke_lksb;
status = sys$deq(lksb->lksb_lock_id, 0, 0, 0);
--poke->poke_use_count;
}
#endif
#ifdef VMS
static int wait_test(SSHORT * iosb)
{
/**************************************
*
* w a i t _ t e s t
*
**************************************
*
* Functional description
* Return true if an I/O event is complete.
*
**************************************/
return *iosb;
}
#endif
#if defined(SUPERSERVER)
void isc_internal_set_config_value(UCHAR key, ULONG * value1, ULONG * value2)
{
switch (key) {
case ISCCFG_DBCACHE_KEY:
JRD_set_cache_default(value1);
break;
case ISCCFG_PRIORITY_KEY:
/*
* This is where you should call your OS specific function to set the
* Process priority (if available).
*/
#ifdef WIN_NT
ULONG priority;
if (*value1 == 2)
priority = HIGH_PRIORITY_CLASS;
else
priority = NORMAL_PRIORITY_CLASS;
if (!SetPriorityClass(GetCurrentProcess(), priority))
{
gds__log("Unable to set process priority.");
}
#endif
break;
case ISCCFG_MEMMAX_KEY:
case ISCCFG_MEMMIN_KEY:
/*
* This is where you should call your OS specific function to set the
* Process priority (if available).
*/
#ifdef WIN_NT
if (*value1 && *value2 && ISC_is_WinNT())
{
HANDLE hndl =
OpenProcess(PROCESS_SET_QUOTA, FALSE, GetCurrentProcessId());
if (hndl) {
ULONG a_value1 = *value1 * 1024;
ULONG a_value2 = *value2 * 1024;
if (!SetProcessWorkingSetSize(hndl, a_value1, a_value2))
{
switch (GetLastError())
{
case ERROR_ACCESS_DENIED:
case ERROR_PRIVILEGE_NOT_HELD:
gds__log("Error setting process working set size, access denied.");
break;
case ERROR_INVALID_PARAMETER:
gds__log("Error setting process working set size, improper range.");
break;
case ERROR_NO_SYSTEM_RESOURCES:
gds__log("Error setting process working set size, insufficient memory.");
break;
default:
gds__log("Error setting process working set size, unknown problem.");
}
*value1 = 0;
*value2 = 0;
}
CloseHandle(hndl);
}
}
#endif
break;
}
}
#endif // SUPERSERVER
#ifdef UNIX
#ifdef AIX_PPC
#define _UNIX95
#endif
#include <grp.h>
#ifdef AIX_PPC
#undef _UNIX95
#endif
SLONG ISC_get_user_group_id(TEXT * user_group_name)
{
/**************************************
*
* I S C _ g e t _ u s e r _ g r o u p _ n a n e
*
**************************************
*
* Functional description
*
* Return user group id if user group name found,
* Otherwise return 0.
*
* --- for UNIX platform ---
*
**************************************/
struct group *user_group;
SLONG n;
n = 0;
if ( (user_group = getgrnam(user_group_name)) )
n = user_group->gr_gid;
return (n);
}
#else
SLONG ISC_get_user_group_id(TEXT * user_group_name)
{
/**************************************
*
* I S C _ g e t _ u s e r _ g r o u p _ n a n e
*
* --- for non-UNIX platform ---
*
**************************************
*
* Functional description
*
* needed to be developed for non-unix platform
*
* Currently it just returns 0.
*
**************************************/
SLONG n;
n = 0;
return (n);
}
#endif /* end of ifdef UNIX */
#ifdef WIN_NT
// Returns the type of OS. TRUE for NT,
// FALSE for the 16-bit based ones (9x/ME, ...).
//
BOOLEAN ISC_is_WinNT()
{
OSVERSIONINFO OsVersionInfo;
if (!os_type)
{
os_type = 1; /* Default to NT */
/* The first time this routine is called we use the Windows API
call GetVersion to determine whether Windows/NT or Chicago
is running. */
OsVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx((LPOSVERSIONINFO) & OsVersionInfo))
{
if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT)
os_type = 2;
}
}
return (os_type != 2) ? TRUE : FALSE;
}
//____________________________________________________________
//
//
LPSECURITY_ATTRIBUTES ISC_get_security_desc()
{
if (security_attr.lpSecurityDescriptor)
{
return &security_attr;
}
PSECURITY_DESCRIPTOR p_security_desc =
(PSECURITY_DESCRIPTOR) gds__alloc((SLONG)
SECURITY_DESCRIPTOR_MIN_LENGTH);
/* FREE: apparently never freed */
if (!p_security_desc) /* NOMEM: */
{
return NULL;
}
#ifdef DEBUG_GDS_ALLOC
gds_alloc_flag_unfreed((void *) p_security_desc);
#endif
if (!InitializeSecurityDescriptor( p_security_desc,
SECURITY_DESCRIPTOR_REVISION) ||
!SetSecurityDescriptorDacl(p_security_desc, TRUE, (PACL) NULL, FALSE))
{
gds__free(p_security_desc);
return NULL;
}
security_attr.nLength = sizeof(security_attr);
security_attr.lpSecurityDescriptor = p_security_desc;
security_attr.bInheritHandle = TRUE;
return &security_attr;
}
#endif