2023-04-30

Windows 付属の OpenSSH で公開鍵認証のみを有効化

  1. OpenSSH サーバーの有効化
    「設定」→「アプリ」→「オプション機能」→「オプション機能を追加する」の「機能を表示」→「OpenSSH サーバー」を選択して「次へ」をクリック
  2. パスワード認証の無効化
    %programdata%\ssh\sshd_configPasswordAuthentication no を追加
  3. 公開鍵を追加
    標準ユーザーの場合は C:\Users\ユーザー名\.ssh\authorized_keys に、管理ユーザーの場合は C:\ProgramData\ssh\administrators_authorized_keys に追加
  4. サービスの有効化
    サービス「OpenSSH SSH Server」のスタートアップ設定を「自動」に変更

2019-01-06

Ubuntu 16.04 x86_64 で Oracle database 18.3 Docker コンテナ

2018年9月に作ったときのメモが残っていたので投稿。

注意: 2022年現在では gvenzl/oracle-xe を使ったほうが楽。以下の手順では事前に Oracle Database の zip ファイルのダウンロードが必要だが、gvenzl/oracle-xe ならば docker image の中に含まれている。

Docker のインストール

$ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install -y docker-ce

Dockerイメージの作成

事前に LINUX.X64_180000_db_home.zip をダウンロードしておく。
$ git clone https://github.com/oracle/docker-images.git
$ cd docker-images/OracleDatabase/SingleInstance/dockerfiles/18.3.0
$ ln ~/Downloads/LINUX.X64_180000_db_home.zip .
$ cd ..
$ sudo ./buildDockerImage.sh -v 18.3.0 -e
$ sudo groupadd -g 54321 oracle
$ sudo useradd -u 54321 -g oracle oracle
$ sudo mkdir -p /var/oradata/ora183
$ sudo chown -R oracle:oracle /var/oradata

Dockerコンテナの実行

$ sudo docker run --name コンテナ名 -p 1521:1521 -p 5500:5500 -e ORACLE_PWD=manager -v /var/oradata/ora183:/opt/oracle/oradata oracle/database:18.3.0-ee
上記コマンドの引数の説明はここを参照。 ローカルホストの 1521 番ポートにアクセスするとコンテナ内の 1521 番ポートに転送される。
$ sqlplus system/manager@//localhost:1521/ORCLPDB1
ただし、この接続方法だと OOB を通さないので、 クライアントからのSQL実行のキャンセルが効かない。実行キャンセルを行う場合は Docker コンテナのIPアドレスを調べてそこに接続すること。
$ docker inspect --format '{{ .NetworkSettings.IPAddress }}' コンテナ名
172.17.0.2
$ sqlplus system/manager@//172.17.0.2:1521/ORCLPDB1
SGAは以下の設定だった。
SQL> show sga

Total System Global Area 1610608648 bytes
Fixed Size                  8896520 bytes
Variable Size             419430400 bytes
Database Buffers         1174405120 bytes
Redo Buffers                7876608 bytes
SQL> show parameter target

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
archive_lag_target                   integer     0
db_big_table_cache_percent_target    string      0
db_flashback_retention_target        integer     1440
fast_start_io_target                 integer     0
fast_start_mttr_target               integer     0
memory_max_target                    big integer 0
memory_target                        big integer 0
parallel_servers_target              integer     32
pga_aggregate_target                 big integer 512M
sga_target                           big integer 0
target_pdbs                          integer     3

2016-05-08

GUI を使わない synergy の設定

Synergy の設定方法についていろんなブログを見ると GUI での設定方法ばかり(例えばこことかこことか)が載っている。 しかし、msvc 2015 で野良ビルドしたものにはGUIツールが作成されない。(mingw32-makeを使えるようにすれば作成されたかもしれないが、面倒なので確認していない) そこで、GUIを使わずに synergy の設定をすることにした。

最初は Ubuntu と Windows でキーボード・マウスを共有させ、次に SSL対応を行なった。

環境は以下の通り
  • サーバー
    • OS: Ubuntu 12.04
    • Synergy: Ubuntu 12.04 のデフォルトの synergy のバージョンは 1.4.10 と古すぎて Windows 用に野良ビルドしたものからは接続できない。 そこでバージョンを合わせるために 2016-05-07 時点の開発中のバージョンをビルドした
  • クライアント

サーバー(ubuntu)側の設定

し synergys を適当なところに置いた。
以下の内容のファイルを $HOME/.synergy.conf に置いた。
section: screens
 ubuntu:
 windows:
end
section: links
 ubuntu:
  right = windows
 windows:
  left = ubuntu
end
section: screens でスクリーンの名前を定義。ここでは ubuntu と windows の2つを使う。
section: links でスクリーンの位置関係を定義。ubuntu の右側は windows で、windows の左側は ubuntu とする。

synergys を起動するときに引数に --name ubuntu を渡して自分のスクリーン名を指定する。
synergys --name ubuntu
($HOME/.synergy.confのスクリーン名 ubuntu をサーバーのホスト名と同じ名前に変更すれば --name ... は不要)

クライアント(Windows)側の設定

c:\synergy に synergyc.exe, synergyd.exe、その他の様々なDLLを入れる。

まず最初にコンソール上でサーバーに接続できるか確認。
c:\synergy\synergyc.exe --name windows サーバーのIPアドレス
(サーバー側の$HOME/.synergy.confのスクリーン名 windows をクライアントのホスト名と同じ名前に変更すれば --name ... は不要)
サーバー側で synergys が動いていてスクリーン名が一致すればこれで動くはず。

この状態だとログインするたびにコンソール上で synergyc を動かす必要がある。また、ログイン画面や、UAC のダイアログ画面ではキーボード・マウスの共有が効かない。 そこでサービスとしてOS起動時に自動起動させる。

コンソールを管理者モードで起動し、以下のコマンドを実行する。
c:\synergy\synergyd.exe /install
synergyd がサービスとして登録される。
次に synergyd が起動するコマンドを指定する。
レジストリエディタを起動し、以下の値を設定する。
  • \\HKEY_LOCAL_MACHINE\Software\Synergy\Command を作成し c:\synergy\synergyc.exe --name windows サーバーのIPアドレスを設定
  • \\HKEY_LOCAL_MACHINE\Software\Synergy\Elevate を作成し、文字列 1 を設定
以下のコマンドでサービスの再起動。
net stop synergy
net start synergy
キーボード・マウスの共有が効いているか確認し、念のため再起動してログイン画面でも効いているかの確認を行った。

SSL対応

デフォルトでは synergy は暗号化なしでクライアントとサーバーの間でデータをやりとりする。パスワードをタイプすると、ネットワーク上を平文のままパスワードが流れる。
また、クライアントがサーバーに接続するとき、認証がまったくない。 例えば、以下の状況のとき他人が勝手にクライアントを操作してしまうかもしれない。
  1. 自宅ではクライアント(スクリーン名 windows)かサーバー(IP: 192.168.0.2)に接続し、サーバーのキーボード・マウスを使ってクライアントを使っている。
  2. クライアントでは自動的に synergy クライアントが起動する。
  3. 自宅の外にクライアントマシンを持って行って、フリーWifi を使う。
  4. フリーWifiのネットワーク上にIP 192.168.0.2 のマシンが偶然あって、synergy サーバーが偶然動いていて、スクリーン名 windows を偶然受け付けるようになっている。
  5. 他人のマシン 192.168.0.2 のキーボード・マウスから自分のクライアントマシンが操作されてしまう。

サーバー(Ubuntu)側の設定

https://wiki.archlinuxjp.org/index.php/Synergy を参考に以下のことを行なった。
  • libns.so~/.synergy/plugins に置く。
  • SSL証明書とフィンガープリントを作成
    mkdir -p ~/.synergy/SSL/Fingerprints
    openssl req -x509 -nodes -days 365 -subj /CN=Synergy -newkey rsa:1024 -keyout ~/.synergy/SSL/Synergy.pem -out ~/.synergy/SSL/Synergy.pem
    openssl x509 -fingerprint -sha1 -noout -in ~/.synergy/SSL/Synergy.pem > ~/.synergy/SSL/Fingerprints/Local.txt
    sed -e "s/.*=//" -i ~/.synergy/SSL/Fingerprints/Local.txt
    
  • synergys を --enable-crypto オプション付きで起動
    synergys --name ubuntu --enable-crypto
    

クライアント(Windows)側の設定

  • ns.dllc:\synergy\plugins にあるのを確認。
  • サーバー側の ~/.synergy/SSL/Fingerprints/Local.txtc:\synergy\SSL\Fingerprints\TrustedServers.txt にコピー。
    mkdir c:\synergy\SSL
    mkdir c:\synergy\SSL\Fingerprints
    copy Local.txt c:\synergy\SSL\Fingerprints\TrustedServers.txt
    
  • レジストリ \\HKEY_LOCAL_MACHINE\Software\Synergy\Command に以下の値を設定
    c:\synergy\synergyc.exe --name windows --profile-dir c: --enable-crypto サーバーのIPアドレス
    
    (--profile-dir の引数に synergy\plugins を追加した場所に ns.dll があり、synergy\SSL\Fingerprints を追加した場所に TrustedServers.txt がある必要がある。)
  • サービスの再起動
    net stop synergy
    net start synergy
    

synergy を msvc 2015 でコンパイル

SynergyGPL の元でリリースされているフリーソフトウェア。 GPLなので自由にソースコードをダウンロードし、自由に改変し、自由に再配布できる。 ただし、開発元からのダウンロードは有料となっている。GPLのソフトウェアとしてはめずらしい。

ここでは、synergy を msvc 2015 でコンパイルした手順を載せる。ただし、GUIでの設定ツールのコンパイルには失敗している。

事前準備

ここを元に以下のソフトウェアをインストールした。 ただし、バージョンは同じではなく、新しめのものを使っている。

コンパイル

MSVC 2015 の x64 用のコンソールを立ち上げ、環境変数を設定するため以下のbatを実行
SET BONJOUR_SDK_HOME=c:\Program Files (x86)\Bonjour SDK

REM Python 2.7.11
PATH=c:\Python27;%PATH%

REM CMake 3.4.1
PATH=c:\Program Files (x86)\CMake\bin;%PATH%

REM Bonjour SDK
PATH=c:\Program Files\Bonjour SDK\Bin;%PATH%

REM WiX Toolset v3.10
PATH=c:\Program Files (x86)\WiX Toolset v3.10\bin;%PATH%

REM Qt 5.6.0 msvc2015_64
PATH=c:\Qt\Qt5.6.0\5.6\msvc2015_64\bin;%PATH%

REM git in cygwin
PATH=%PATH%;c:\cygwin64\bin
次に synergy のソースコードをチェックアウトする。 ただし、本家のソースコード2016-05-07 の時点では msvc 2015 に対応していない。 そこで代わりにこちらの vc2015-qt55 ブランチを使った。(本家のソースコードの msvc 2015 対応が完了したら本家を使うべき)
git clone --depth=1 https://github.com/sheavner/synergy.git
git checkout vc2015-qt55
コンパイル実行。 -g の後ろの数字により MSVC のバージョンを指定している。synergy/ext/toolchain/commands1.py の win32_generators に値と MSVC のバージョンの対応が載っている。 本家が対応したときには msvc 2015 に対応する数字は 12 ではないかもしれない。
hm conf -g 12
hm build
mingw32-make がないというエラーで終了する。多分、ここに載っている Qt SDK 2010.02 の中に minw32-make が入っているのだと思われるが未確認。 この時点までに作成されたものはチェックアウトしたディレクトリの bin/Release の下に入っている。 インストーラやGUIでの設定ツールは作成されていないが、コマンドラインから使えるツールは作成されていたので、ここでコンパイルは完了とする。

インストール

bin/Release の下のファイルをまるごと別のディレクトリにコピー。

これで完了。
GUIを使わない設定の方法はここに記載した。

2015-01-12

Undocumented OCI Handle Attributes

This entry has been obsolete since Oracle 12.2. The following attributes are documented in Oracle 12.2 OCI manual.


OCI_ATTR_RECEIVE_TIMEOUT and OCI_ATTR_SEND_TIMEOUT are defined in oci.h but not documented in Oracle 12.1 OCI manual. I guess their specifications as follows.

Server Handle Attributes

OCI_ATTR_RECEIVE_TIMEOUT

   Mode
   READ/WRITE

   Description
   Specify the receive timeout in milliseconds.
   Specifying zero means no timeout.

   Attribute Data Type
   ub4 */ub4

OCI_ATTR_SEND_TIMEOUT

   Mode
   READ/WRITE

   Description
   Specify the send timeout in milliseconds.
   Specifying zero means no timeout.

   Attribute Data Type
   ub4 */ub4

I checked OCI_ATTR_RECEIVE_TIMEOUT on Linux with various Oracle versions.
Oracle 10.2 and earlier
"ORA-24315: illegal attribute type" on setting the attribute
Oracle 11.1
"ORA-03113: end-of-file on communication channel" on timeout
Oracle 11.2 and later
"ORA-12609: TNS: Receive timeout occurred" on timeout

2015-01-02

gcc で _BitScanForward & _BitScanReverse 互換関数、MSVC で __builtin_clz & __builtin_ctz 互換関数

gcc には __builtin_clz, __builtin_ctz という組み込み関数があり、MSVC(Microsoft Visual C++) には _BitScanForward, _BitScanReverse という組み込み関数がある。 とあるアプリを Windows でコンパイルしようとしたところ、gcc の場合は __builtin_clz, __builtin_ctz を使っているところがあった。MSVC にも同じような関数があったよなと思い、調べたことを以下の順番で書く。
  • __builtin_clz, __builtin_ctz, _BitScanForward, _BitScanReverse の仕様
  • MSVC の _BitScanForward, _BitScanReverse を使った __builtin_clz, __builtin_ctz 互換関数
  • gcc の __builtin_clz, __builtin_ctz を使った _BitScanForward, _BitScanReverse 互換関数
  • ついでに、gcc のインラインアセンブラを使った _BitScanForward, _BitScanReverse 互換関数

__builtin_clz, __builtin_ctz, _BitScanForward, _BitScanReverse の仕様

  • int __builtin_clz(unsigned int)
gccの組み込み関数。 clz は Count Leading Zeros の略で、上位ビットの0の個数を返す。 例えば引数の値が二進数で 00000000 10110011 11111100 11010100 のとき、上位ビットの連続する 0 の数は8個なので、戻り値は 8 となる。 全ビットが0のときの戻り値は未定義。
  • int __builtin_ctz(unsigned int)
gccの組み込み関数。 ctz は Count Trailing Zeros の略で、下位ビットの0の個数を返す。 例えば引数の値が二進数で 00000000 10110011 11111100 11010100 のとき、下位ビットの連続する 0 の数は2個なので、戻り値は 2 となる。 全ビットが0のときの戻り値は未定義。
  • unsigned char _BitScanForward(unsigned long *Index, unsigned long Mask)
MSVCの組み込み関数。 下位ビットから値が1のビットを検索し、最初に見つかった値1のビットの位置を *Index に設定する。全ビットが0のときの戻り値は0で、それ以外の場合は非0値。 例えば引数 Mask の値が二進数で 00000000 10110011 11111100 11010100 のとき、下位ビットから見て最初の1の位置は2(最下位ビットの位置は0)なので、*Index に2を設定したあと、非0の値が戻り値となる。
下位から見て最初の1が見つかるまでのビットはすべて0なので、最初の1の位置は、下位の連続する0の個数と同じ値となる。したがって、__builtin_ctz を使えば _BitScanForward が実装できるし、_BitScanForward を使えば、__builtin_ctz を実装できる。
  • unsigned char _BitScanReverse(unsigned long *Index, unsigned long Mask)
MSVCの組み込み関数。 上位ビットから値が1のビットを検索し、最初に見つかった値1のビットの位置を *Index に設定する。全ビットが0のときの戻り値は0で、それ以外の場合は非0値。 例えば引数 Mask の値が二進数で 00000000 10110011 11111100 11010100 のとき、上位ビットから見て最初の1の位置は23(最下位ビットの位置は0)なので、*Index に23を設定したあと、非0の値が戻り値となる。
上位から見て最初の1が見つかるまでのビットはすべて0なので、最初の1の位置は上位の連続する0の個数から簡単な計算で求まる。したがって、__builtin_clz を使えば _BitScanReverse が実装できるし、_BitScanReverse を使えば、__builtin_clz を実装できる。

MSVC の _BitScanForward, _BitScanReverse を使った __builtin_clz, __builtin_ctz 互換関数

#include <intrin.h>

int __builtin_clz(unsigned int n)
{
    unsinged long index;
    /* n が0のときの __builtin_clz の戻り値は未定義なので、
     * _BitScanReverse の戻り値チェックは割愛する。
     */
    _BitScanReverse(&index, n);
    return 31 - index;
}

int __builtin_ctz(unsigned int n)
{
    unsinged long index;
    /* n が0のときの __builtin_ctz の戻り値は未定義なので、
     * _BitScanForward の戻り値チェックは割愛する。
     */
    _BitScanForward(&index, n);
    return index;
}

gcc の __builtin_clz, __builtin_ctz を使った _BitScanForward, _BitScanReverse 互換関数

unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
    if (Mask) {
        *Index = __builtin_ctz(Mask);
        return 1;
    } else {
        /* 戻り値が0のとき、*Index がどうなるかは未定義。*/
        return 0;
    }
}

unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
    if (Mask) {
        *Index = 31 - __builtin_clz(Mask);
        return 1;
    } else {
        /* 戻り値が0のとき、*Index がどうなるかは未定義。*/
        return 0;
    }
}

gcc のインラインアセンブラを使った _BitScanForward, _BitScanReverse 互換関数

unsigned char inline _BitScanForward(unsigned int *Index, unsigned int Mask)
{
    unsigned char rv;
    __asm(
          "bsfl %2, %0;"
          "setne %1;"
          : "=r"(*Index),"=r"(rv)
          : "g"(Mask)
          : "cc");
    return rv;
}

unsigned char inline _BitScanReverse(unsigned int *Index, unsigned int Mask)
{
    unsigned char rv;
    __asm(
          "bsrl %2, %0;"
          "setne %1;"
          : "=r"(*Index),"=r"(rv)
          : "g"(Mask)
          : "cc");
    return rv;
}

2012-09-07

C言語でのOracle外部プロシージャ

Oracleの外部プロシージャとは、簡単に言うと、PL/SQL以外の言語で書かれたストアドプロシージャのことを指す。 Oracle本家でサポートしているのは以下の3つ。 サードパーティーでは perl が使える。 Oracle® Databaseアドバンスト・アプリケーション開発者ガイドを参照しながらC言語で簡単な外部プロシージャを作ってみる。
まず、system ユーザーでログインして試験用ユーザーを作成
~$ sqlplus

SQL*Plus: Release 10.2.0.1.0 - Production on Fri Sep 7 13:22:00 2012

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

Enter user-name: system/manager

Connected to:
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production

SQL> create user extproc_test identified by extproc_test                    
  2  default tablespace users temporary tablespace temp;

User created.

SQL> grant connect, resource, create library to extproc_test;

Grant succeeded.

次に試験用ユーザーでログインして、共有ライブラリの場所を指定。
SQL> connect extproc_test/extproc_test 
Connected.
SQL> create library extproc_test as '${ORACLE_HOME}/lib/extproc_test.so';
  2  /

Library created.

$ORACLE_HOME/lib, $ORACLE_HOME/bin 以外の場所に共有ライブラリを置くときは 環境変数EXTPROC_DLLSを設定すること。
次にSQL関数を作成。
SQL> create function add_func(x pls_integer, y pls_integer)                       
  2  return pls_integer
  3  as language C library extproc_test name "add_func";
  4  /

Function created.

次にC言語の関数を作成。
int add_func(int x, int y)
{
  return x + y;
}
pls_integer はデフォルトでは C 言語の int にマッピングされる。
コンパイルして $ORACLE_HOME/lib にコピー。
$ gcc -shared -o extproc_test.so extproc_test.c
$ cp extproc_test.so $ORACLE_HOME/lib
実行してみる。
SQL> select add_func(1, 2) from dual;

ADD_FUNC(1,2)
-------------
            3
期待通りに動いた。
試しにNULLを渡してみる。
SQL> select add_func(1, NULL) from dual;
select add_func(1, NULL) from dual
                              *
ERROR at line 1:
ORA-01405: fetched column value is NULL
C言語では NULL かどうかの判断ができないから当然か。。。
C言語側にNULLかどうかのフラグを渡せるよう関数定義を修正する。
SQL> create or replace function add_func(x pls_integer, y pls_integer)
  2  return pls_integer
  3  as language c library extproc_test name "add_func"
  4  parameters(x, x indicator, y, y indicator, return indicator);
  5  /

Function created.

parameters の指定に従い、C言語の関数定義も変更する。
#include 

int add_func(int x, short x_ind, int y, short y_ind, short *rind)
{
  if (x_ind || y_ind) { /* x または y が NULL のとき */
    *rind = OCI_IND_NULL; /* 戻り値は NULL */
    return 0;
  }
  *rind = 0; /* 戻り値は非NULL */
  return x + y; /* 戻り値 */
}
再度コンパイルしてコピー。
$ gcc -shared -o extproc_test.so extproc_test.c -I$ORACLE_HOME/rdbms/public
$ cp extproc_test.so $ORACLE_HOME/lib
実行してみる。
SQL> select add_func(1, NULL) from dual;
select add_func(1, NULL) from dual
                              *
ERROR at line 1:
ORA-28576: lost RPC connection to external procedure agent
使用中の共有ライブラリを上書きしたせいか、それともメモリ上には古い共有ライブラリが 載っているのにOracle側の関数定義を変えたせいか。 まあ、どちらにしても、これでextprocプロセスが再起動してくれれば次はうまく行くはず。
SQL> select add_func(1, NULL) from dual;

ADD_FUNC(1,NULL)
----------------

今度は動いた。
念のため非NULL値の試験も行う。
SQL> select add_func(1, 2) from dual;

ADD_FUNC(1,2)
-------------
            3
動いた。

以上。