CL

76. API : QSYGETPH 仮想ユーザー・ログインの方法

API: QSYGETPH は IBM API解説書では「プロファイル・ハンドルの取得」
という表題で紹介されているために、うっかり見逃してしまう API であるが、この API によれば
IBM System i の堅牢なユーザー管理システムを利用できる適用業務を構築することができる。
もう少し簡単に説明してみよう。
例えばC/S (クライアント/サーバー) や Web適用業務においてサイン・オンに代わる
ユーザー認証をどのように作成するか? ということである。
ユーザー認証フォーム(HTML)を作成して、エンド・ユーザーにユーザー名やパスワードを
入力させて フォーム SUBMIT したのでは、入力されたユーザーとパスワードは
そのままの形でTCP/IPストリームとしてインターネット回線を流れていくことになり
第三者の傍受によって、いとも簡単にユーザー,パスワードを盗まれてしまうだろう。

このような脆弱なユーザー認証を防ぐにはやはり System i の堅牢なサイン・オンの
システムを利用するに限ることはいうまでも無い。
5250 エミュレータで利用されているサイン・オンによる認証の仕組みは
ここで紹介する API : QSYGETPH によって実現することができる。
つまり QSYGETPH は 5250エミュレータのサインオンの仕組みを再現するための API である。
QSYGETPH とは「プロファイル・ハンドルの取得」という比較的わかりにくい表現で
紹介されているために System i の開発者に利用されている頻度が少ないのではないかと思われる。
プロファイル・ハンドル」とはユーザー・プロフィールによる環境を構築したときを個別に
識別する識別子のことである。
識別子(ハンドル)とは i5/OS によって重なりのないように自動生成された一意的な値として
生成される。
つまり同じ記号や番号として偶然にも他のものと重なることがないように i5/OS によって
ランダムに発生した記号であり、これによって現在、実行中のユーザー環境を識別するのである。
別の話になるが、あなたも既に自分の Windows PC 上に多くのウィンドウを開いているはずである。
Windows OS は、これらのすべてのウィンドウにやはり「ウィンドウ・ハンドル」と呼ばれる
識別子を持っていて、それらを個別に制御しているのである。
このように複数個、存在する実行中のオブジェクトを識別するための識別子のことを「ハンドル」と呼ぶ。
前置きが長くなってしまったが System i の開発者には「ハンドル」という言葉にはあまり
馴染みがないと思われるので解説した次第である。

仮想ログイン (サイン・オン) の流れ

【解説】

仮想ユーザー環境とは QSYGETPH によってハンドルを取得したときに始まって
QSYRLSPH によってハンドルが解放されるまでのあいだの環境のことである。
つまり QSYGETPH によってサイン・オンされて QSYRLSPH によってサイン・オフされると考えてよい。
ここでは API による仮想ユーザー環境の構築と i5/OS リリース別の考慮点についても
現実的で詳細な解説を加えていこうと思う。

QSYGETPH: プロファイル・ハンドルの取得

パラメータ

必須パラメータ・グループ:

1.ユーザーID入力Char(10)
2.パスワード入力Char(*)
3.プロファイル・ハンドル出力Char(12)

任意選択パラメータ:

4.エラー・コード入出力Char(*)

任意選択パラメータ:

5.パスワードの長さ入力Binary(4)
6.パスワードの CCSID入力Binary(4)

1. ユーザーID

ユーザー・ハンドルを生成する、つまり仮想ログインするユーザー・プロフィールの
10桁の名前。特殊値として *CURRENT を指定すると現在のユーザー名のハンドルを
取得することができる。
現在のユーザー(*CURRENT)を取得する理由は、別のユーザーとしてログインしたいときに
現在のユーザーのハンドルを取得しておいてログインしたユーザーを終了したときに
現在のユーザーに戻すために使用する。

2. パスワード

上記で指定するユーザーのパスワード。OS V5R2M0 までは 10桁であるが
V5R3M0 以上では最大128桁までのパスワードを指定することができる。
また特殊値として *NOPWD とはパスワードがないことを意味する。
例えば HTTP サーバーでの省略時のユーザー : QTMHHTTP はパスワードを持たないので
*NOPWD を指定する必要がある。
また QSYS, QDOC, QSPL, QRJE, ... のように、QSYGETPH を使ってもハンドルの取得で
許されていないユーザーも存在する。

3. プロファイル・ハンドル

QSYGETPH によって自動生成される 12 桁のランダム・ストリングとしての
ユーザー環境を識別するための識別子。

5. パスワードの長さ

OS V5R3M0 以降に追加されたパラメータであり、パスワードの長さの指定である。
このパラメータは任意パラメータとして V5R3M0 から初めて紹介されたが
V5R3M0 では必須パラメータであり、正しく指定していないと QSYGETPH
エラーとなって動作しない。これはOS V5R3M0 のバグであり、とうとう最後まで
IBM によって修正されることはなかった。
弊社が原因不明として苦しめられたバグのひとつである。( V5R3M0 はバグの多い問題のあるリリースであった )
IBM は OS Ver5.4 で、このバグを修正して「任意指定パラメータ」のマニュアルの
とおりに指定していなくてもエラーとはしないように正しい動作に改訂されている。

6. パスワードの CCSID

通常では 65535 を指定しておけばよい。

これはユーザーが任意に入力したユーザーで仮想ログインするプログラムである。
特にこの CLP のサンプル・ソースでは面白い例を用意した。
5250 エミュレーターに良く似たサイン・オン画面による仮想ログインのサンプルを
作ってみようというのである。
仮想サイン・オン画面で、ユーザーとパスワードを入力して実行キーを押すと実際のサインオンと
同じ初期プログラムが実行される仕組みを作ろうというのである。
ユーザーの初期プログラムを終了させれば、この仮想サインオンもまたサインオフされる。
このサンプル・ソースの内容を見れば System i のサイン・オンがどのように行なわれているかを
知ることができ、独自の認証システムの構築に造詣を与えてくれるはずである。

【仮想サイン・オン画面】

【 サンプル・ソース:TESTGETPH 】
0001.00              PGM                                                          
0002.00 /*---------------------------------------------------------*/             
0003.00 /*   TESTGETPH :  QSYGETPH のテスト                        */             
0004.00 /*---------------------------------------------------------*/             
0005.00              DCL        VAR(&MSG) TYPE(*CHAR) LEN(132)                    
0006.00              DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)                    
0007.00              DCL        VAR(&MSGDTA) TYPE(*CHAR) LEN(132)                 
0008.00              DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)                    
0009.00              DCL        VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)                 
0010.00              DCL        VAR(&SBS) TYPE(*CHAR) LEN(20)                     
0011.00              DCLF       FILE(TEST.COM/TESTGETPD)                          
0012.00              DCL        VAR(&OS400) TYPE(*CHAR) LEN(6)                    
0013.00              DCL        VAR(&PRFHND) TYPE(*CHAR) LEN(12)                  
0014.00              DCL        VAR(&APIERR) TYPE(*CHAR) LEN(116) +               
0015.00                           VALUE(X'000074') /* 2 進数  */                  
0016.00              DCL        VAR(&NULL4) TYPE(*CHAR) LEN(4) +                  
0017.00                           VALUE(X'00000000')                              
0018.00              DCL        VAR(&PASSLEN) TYPE(*CHAR) LEN(4) +                
0019.00                           VALUE(X'000A') /* 10 */                         
0020.00              DCL        VAR(&CCSID) TYPE(*CHAR) LEN(4) +                  
0021.00                           VALUE(X'FFFF') /* 65535 */                      
0022.00              DCL        VAR(&INLPGM) TYPE(*CHAR) LEN(10)                  
0023.00              DCL        VAR(&INLPGMLIB) TYPE(*CHAR) LEN(10)    
0024.00              DCL        VAR(&API) TYPE(*CHAR) LEN(10)                   
0025.00              MONMSG     MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))         
0026.00                                                                         
0027.00  /*(1) OS400 のリリースを検索する */                                    
0028.00              RTVDTAARA  DTAARA(QGPL/QSS1MRI (1 6)) RTNVAR(&OS400)       
0029.00                                                                         
0030.00  /*(2) サイン・オン画面を表示してユーザー、パスワードを受け取る */      
0031.00              CHGVAR     VAR(©RIGHT) VALUE('(C) COPYRIGHT OFFICE +   
0032.00                           QUATTRO 2012-')                               
0033.00              RTVJOBA    JOB(&DEVNAME)                                   
0034.00              RTVSYSVAL  SYSVAL(QCTLSBSD) RTNVAR(&SBS)                   
0035.00              CHGVAR     VAR(&SBSNAME) VALUE(%SST(&SBS 1 10))            
0036.00              SNDRCVF    RCDFMT(SIGNON)                                  
0037.00              IF         COND(&IN03 *EQ '1') THEN(RETURN)                
0038.00                                                                         
0039.00  /*(3) QSYGETPH でログイン・ハンドルを生成する */                       
0040.00              IF         COND(&OS400 *LT 'V5R3M0') THEN(DO) /* +         
0041.00                           V5R3M0 未満  */                               
0042.00              CALL       PGM(QSYGETPH) PARM(&USERID &PASSWRD &PRFHND +   
0043.00                           &APIERR)                                      
0044.00              ENDDO      /* V5R3M0 未満  */                              
0045.00              ELSE       CMD(DO) /* V5R3M0 以上  */                      
0046.00              CHGVAR     VAR(%BIN(&PASSLEN)) VALUE(10)                   
0047.00              CHGVAR     VAR(%BIN(&CCSID)) VALUE(65535)                  
0048.00              CALL       PGM(QSYGETPH) PARM(&USERID &PASSWRD &PRFHND +       
0049.00                           &APIERR &PASSLEN &CCSID)                          
0050.00              ENDDO      /* V5R3M0 以上  */                                  
0051.00              IF         COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO)         
0052.00              CHGVAR     VAR(&API) VALUE('QSYGETPH')                         
0053.00              GOTO       APIERR                                              
0054.00              ENDDO                                                          
0055.00                                                                             
0056.00  /*(4)  指定したユーザーで JOB を開始する */                                
0057.00              CALL       PGM(QWTSETP) PARM(&PRFHND &APIERR)                  
0058.00              IF         COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO)         
0059.00              CHGVAR     VAR(&API) VALUE('QWTSETP')                          
0060.00              GOTO       APIERR                                              
0061.00              ENDDO                                                          
0062.00                                                                             
0063.00  /*(5) ユーザー・プロフィールで登録されている初期プログラムを起動する */    
0064.00              RTVUSRPRF  USRPRF(*CURRENT) INLPGM(&INLPGM) +                  
0065.00                           INLPGMLIB(&INLPGMLIB)                             
0066.00              CALL       PGM(&INLPGMLIB/&INLPGM)                             
0067.00                                                                             
0068.00  /*(6) ハンドルを解放して JOB を終了する */                                 
0069.00              CALL       PGM(QSYRLSPH) PARM(&PRFHND)                         
0070.00                                                                             
0071.00              RETURN                                                         
0072.00                                                                           
0073.00  APIERR:                                                                  
0074.00              CHGVAR     VAR(&MSGID) VALUE(%SST(&APIERR 9 7))              
0075.00              CHGVAR     VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100))          
0076.00              CHGVAR     VAR(&MSGF) VALUE('QCPFMSG   ')                    
0077.00              CHGVAR     VAR(&MSGFLIB) VALUE('QSYS      ')                 
0078.00              SNDPGMMSG  MSG('API: ' *CAT &API *TCAT +                     
0079.00                           ' でエラーがありました。 ') +                   
0080.00                           TOMSGQ(*TOPGMQ) MSGTYPE(*COMP)                  
0081.00              GOTO       SNDERR                                            
0082.00  ERROR:      RCVMSG     MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) +               
0083.00                           MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +     
0084.00                           MSGFLIB(&MSGFLIB)                               
0085.00  SNDERR:     IF         COND(&MSGID *EQ ' ') THEN(DO)                     
0086.00              SNDPGMMSG  MSG(&MSG) TOMSGQ(*SYSOPR)                         
0087.00              ENDDO                                                        
0088.00              ELSE       CMD(DO)                                           
0089.00              SNDPGMMSG  MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +              
0090.00                           MSGDTA(&MSGDTA) TOMSGQ(*TOPGMQ) +               
0091.00                           MSGTYPE(*ESCAPE)                                
0092.00              ENDDO                                                        
0093.00              ENDPGM                                                       
【 サンプル画面ソース:TESTGETPH 】
0001.00      A                                      DSPSIZ(24 80 *DS3)                      
0002.00      A          R SIGNON                                                            
0003.00      A                                      CF03(03 ' 終了 ')                       
0004.00      A                                      CLEAR                                   
0005.00      A                                      BLINK                                   
0006.00      A                                 01 23'      仮想サイン・オン           '     
0007.00      A                                      DSPATR(HI)                              
0008.00      A                                 02 48' システム . . . . :'                   
0009.00      A*           SYSNAME        8   O 02 70                                        
0010.00      A                               O 02 70SYSNAME                                 
0011.00      A                                 03 48' サブシステム . . :'                   
0012.00      A            SBSNAME       10   O 03 70                                        
0013.00      A                                 04 48' 表示装置 . . . . :'                   
0014.00      A            DEVNAME       10   O 04 70                                        
0015.00      A                                 06 17' ユーザー . . . . . . . . . . . .'     
0016.00      A            USERID        10   B 06 53                                        
0017.00      A                                 07 17' パスワード . . . . . . . . . . .'     
0018.00      A            PASSWRD       10   I 07 53                                        
0019.00      A                                      DSPATR(ND)                              
0020.00      A                                 08 17' プログラム/プロシージャー . . .'     
0021.00      A            PROGRAM       10   B 08 53CHECK(LC)                               
0022.00      A                                 09 17' メニュー . . . . . . . . . . . .'     
0023.00      A            MENU          10   B 09 53CHECK(LC)                               
0024.00      A                                 10 17' 現行ライブラリー . . . . . . . .'
0025.00      A            CURLIB        10   B 10 53CHECK(LC)                          
0026.00      A  99        QSNERROR      80   O 24 01DSPATR(HI)                         
0027.00      A            COPYRIGHT     40   O 24 40DSPATR(HI)                         
0028.00      A*           UBUFFER      128   H                                         
【解説】

このプログラムは OS V3R7M0 - V5R3M0, および V5R3M0 以上での動作をカバーしている。

0012.00              DCL        VAR(&OS400) TYPE(*CHAR) LEN(6)
                      :
0027.00  /*(1) OS400 のリリースを検索する */                              
0028.00              RTVDTAARA  DTAARA(QGPL/QSS1MRI (1 6)) RTNVAR(&OS400) 

によって QGPL/QSS1MRI *DTAARA の 1-6 桁に記述されているOS リリースを読み取って、

0039.00  /*(3) QSYGETPH でログイン・ハンドルを生成する */                             
0040.00              IF         COND(&OS400 *LT 'V5R3M0') THEN(DO) /* +               
0041.00                           V5R3M0 未満  */                                     
0042.00              CALL       PGM(QSYGETPH) PARM(&USERID &PASSWRD &PRFHND +         
0043.00                           &APIERR)                                            
0044.00              ENDDO      /* V5R3M0 未満  */                                    
0045.00              ELSE       CMD(DO) /* V5R3M0 以上  */                            
0046.00              CHGVAR     VAR(%BIN(&PASSLEN)) VALUE(10)                         
0047.00              CHGVAR     VAR(%BIN(&CCSID)) VALUE(65535)                        
0048.00              CALL       PGM(QSYGETPH) PARM(&USERID &PASSWRD &PRFHND +         
0049.00                           &APIERR &PASSLEN &CCSID)                            
0050.00              ENDDO      /* V5R3M0 以上  */                                    
0051.00              IF         COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO)           
0052.00              CHGVAR     VAR(&API) VALUE('QSYGETPH')                           
0053.00              GOTO       APIERR                                                
0054.00              ENDDO                                                            

のようにして OS V5R3M0 以上であれば パスワード長つきのパラメータで実行して、それ未満であれば
パスワード長は指定せずに実行する。

これによって

  • OS V5R3M0 以降とそれ未満の OS環境の両方をサポート
  • OS V5R3M0 での OS のバグの回避

の両方ともを解決している。
次に QSYGETPH で取得したハンドルを使って

0056.00  /*(4)  指定したユーザーで JOB を開始する */                                
0057.00              CALL       PGM(QWTSETP) PARM(&PRFHND &APIERR)

によって仮想ユーザー環境が開始されるので、RTVUSRPRF を使って次のように
このユーザーの初期プログラムを検索して実行する。

0063.00  /*(5) ユーザー・プロフィールで登録されている初期プログラムを起動する */    
0064.00              RTVUSRPRF  USRPRF(*CURRENT) INLPGM(&INLPGM) +                  
0065.00                           INLPGMLIB(&INLPGMLIB)                             
0066.00              CALL       PGM(&INLPGMLIB/&INLPGM) 
【実行された初期画面】

これでユーザー環境のJOBを開始して実行することができる。
最後にこの JOB を F3=終了 で終了すると仮想環境は終了して

0068.00  /*(6) ハンドルを解放して JOB を終了する */                                 
0069.00              CALL       PGM(QSYRLSPH) PARM(&PRFHND)

によってハンドルを解放して終了する。
このような API : QSYGETPH を使って仮想ログイン環境を実現できれば

  • C/S モデルでのユーザー認証
  • Web アプリケーションでのユーザー認証

のモデルを構築することができる。
QSYGETPH に始まる認証API は System i の堅牢な認証システムを使ったユーザー認証に
大いに役立つはずである。