GSS-API のプログラミング

補助的な関数

クライアントプログラムとサーバープログラムが期待どおりに機能するには、他にもいくつかの関数が必要です。このような関数はほとんどが値を表示したりするもので、プログラムの基本機能には必ずしも必要ではありません。ここではプログラムの完全性のためだけに示しています。

ただし、2 つの関数 send_token()recv_token() は重要です。この 2 つの関数はコンテキストのトークンとメッセージを実際に転送します。この 2 つの関数は純粋に基本的な関数であり、ファイル記述子を開いて読み書きします。普通でしかも GSS-API には直接関係はありませんが、別に説明するだけの価値はあります。

さまざまなサポート関数

次に、さまざまなサポート関数について説明します。


例 A–17


/*
 * Copyright 1994 by OpenVision Technologies, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appears in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of OpenVision not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission. OpenVision makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#if !defined(lint) && !defined(__CODECENTER__)
static char *rcsid = "$Header: /afs/athena.mit.edu/astaff/project/krbdev/.cvsroot
/src/appl/gss-sample/gss-misc.c,v 1.15 1996/07/22 20:21:20 marc Exp $";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>

#include <gssapi/gssapi.h>
#include "gss-misc.h"
#include <stdlib.h>

FILE *display_file;
extern gss_OID g_mechOid;


static void display_status_1(char *m, OM_uint32 code, int type);

static int write_all(int fildes, char *buf, unsigned int nbyte)
{
     int ret;
     char *ptr;

     for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
          ret = write(fildes, ptr, nbyte);
          if (ret < 0) {
               if (errno == EINTR)
                    continue;
               return(ret);
          } else if (ret == 0) {
               return(ptr-buf);
          }
     }

     return(ptr-buf);
}

static int read_all(int fildes, char *buf, unsigned int nbyte)
{
     int ret;
     char *ptr;

     for (ptr = buf; nbyte; ptr += ret, nbyte -= ret) {
          ret = read(fildes, ptr, nbyte);
          if (ret < 0) {
               if (errno == EINTR)
                    continue;
               return(ret);
          } else if (ret == 0) {
               return(ptr-buf);
          }
     }

     return(ptr-buf);
}

static void display_status_1(m, code, type)
     char *m;
     OM_uint32 code;
     int type;
{
     OM_uint32 maj_stat, min_stat;
     gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
     OM_uint32 msg_ctx;

     msg_ctx = 0;
     while (1) {
          maj_stat = gss_display_status(&min_stat, code,
                                       type, g_mechOid,
                                       &msg_ctx, &msg);
          if (maj_stat != GSS_S_COMPLETE) {
                  if (display_file) {
                        fprintf(display_file, "error in gss_display_status"
                                        " called from <%s>\n", m);
                  }
                  break;
          }
          else if (display_file)
                fprintf(display_file, "GSS-API error %s: %s\n", m,
                      (char *)msg.value);
          if (msg.length != 0)
                (void) gss_release_buffer(&min_stat, &msg);

          if (!msg_ctx)
               break;
     }
}

/*
 * 関数: display_status
 *
 * 目的: GSS-API メッセージを表示する
 *
 * 引数:
 *
 *      msg             メッセージと一緒に表示する文字列
 *      maj_stat        GSS-API メジャー状態コード
 *      min_stat        GSS-API マイナー状態コード
 *
 * 効果:
 *
 * maj_stat と min_stat に関連する GSS-API メッセージが stderr に表示される。
 * 各メッセージの前には「GSS-API error <msg>:」が、後には復帰改行が
 * 出力される。
 */
void display_status(msg, maj_stat, min_stat)
     char *msg;
     OM_uint32 maj_stat;
     OM_uint32 min_stat;
{
     display_status_1(msg, maj_stat, GSS_C_GSS_CODE);
     display_status_1(msg, min_stat, GSS_C_MECH_CODE);
}


/*
 * 関数: display_ctx_flags
 *
 * 目的: コンテキスト起動から戻されたフラグを人が読める形式で表示する。
 *
 * 引数:
 *
 *      int             ret_flags
 *
 * 効果:
 *
 * コンテキストフラグに対応する文字列が stdout に出力される。各文字列の
 * 前には「context flag: 」が、後には復帰改行が出力される。
 */

void display_ctx_flags(flags)
     OM_uint32 flags;
{
     if (flags & GSS_C_DELEG_FLAG)
          fprintf(display_file, "context flag: GSS_C_DELEG_FLAG\n");
     if (flags & GSS_C_MUTUAL_FLAG)
          fprintf(display_file, "context flag: GSS_C_MUTUAL_FLAG\n");
     if (flags & GSS_C_REPLAY_FLAG)
          fprintf(display_file, "context flag: GSS_C_REPLAY_FLAG\n");
     if (flags & GSS_C_SEQUENCE_FLAG)
          fprintf(display_file, "context flag: GSS_C_SEQUENCE_FLAG\n");
     if (flags & GSS_C_CONF_FLAG )
          fprintf(display_file, "context flag: GSS_C_CONF_FLAG \n");
     if (flags & GSS_C_INTEG_FLAG )
          fprintf(display_file, "context flag: GSS_C_INTEG_FLAG \n");
}

void print_token(tok)
     gss_buffer_t tok;
{
    int i;
    unsigned char *p = tok->value;

    if (!display_file)
        return;
    for (i=0; i < tok->length; i++, p++) {
        fprintf(display_file, "%02x ", *p);
        if ((i % 16) == 15) {
            fprintf(display_file, "\n");
        }
    }
    fprintf(display_file, "\n");
    fflush(display_file);
}

send_token()recv_token()

この 2 つの関数はクライアントとサーバー間でデータを送受信します。なお、マルチプロセスアプリケーションでは、プロセス間でデータを送受信できます。トークンと同様にメッセージも送受信するため、名前が若干間違っているように思えるかもしれません。この 2 つの関数は自分が処理する内容を意識しません。

send_token()

send_token() はトークンまたはメッセージを送信します。


例 A–18 send_token()


/*
 * 関数: send_token
 *
 * 目的: トークンをファイル記述子に書き込む
 *
 * 引数:
 *
 *      s               (r) 開いたファイル記述子
 *      tok             (r) 書き込むトークン
 *
 * 戻り値: 成功した場合は 0、失敗した場合は -1
 *
 * 効果:
 *
 * send_token はまずトークンの長さ (ネットワーク上の長さ) を、次にトークンの
 * データをファイル記述子 s に書き込みます。成功した場合は 0 を戻し、
 * エラーが発生したり、すべてのデータを書き込むことができなかった場合は 
 * -1 を戻します。
 */
int send_token(s, tok)
     int s;
     gss_buffer_t tok;
{
     int len, ret;

     len = htonl((OM_uint32)tok->length);
     ret = write_all(s, (char *) &len, sizeof(int));
     if (ret < 0) {
          perror("sending token length");
          return -1;
     } else if (ret != 4) {
         if (display_file)
             fprintf(display_file,
                     "sending token length: %d of %d bytes written\n",
                     ret, 4);
          return -1;
     }

     ret = write_all(s, tok->value, (OM_uint32)tok->length);
     if (ret < 0) {
          perror("sending token data");
          return -1;
     } else if (ret != tok->length) {
         if (display_file)
             fprintf(display_file,
                     "sending token data: %d of %d bytes written\n",
                     ret, tok->length);
         return -1;
     }

     return 0;
}

recv_token()

recv_token() はトークンまたはメッセージを受信します。


例 A–19 recv_token()


/*
 * 関数: recv_token
 *
 * 目的: ファイル記述子からトークンを読み取ります
 *
 * 引数:
 *
 *      s               (r) 開いたファイル記述子
 *      tok             (w) 読み取るトークン
 *
 * 戻り値: 成功した場合は 0、失敗した場合は -1
 *
 * 効果:
 *
 * recv_token はまずトークンの長さ (ネットワーク上の長さ) を読み取り、その
 * データを保持するメモリーを割り当て、そして、ファイル記述子 s からトークン
 * のデータを読み取る。必要であれば、長さとデータの読みとりを中止する。
 * 成功した場合、gss_release_buffer でトークンを解放する必要がある。
 * 成功した場合は 0 を戻し、エラーが発生したり、すべてのデータを読み取る
 * ことができなかった場合は -1 を戻す。
 */
int recv_token(s, tok)
     int s;
     gss_buffer_t tok;
{
     int ret, len;

     ret = read_all(s, (char *) &len, sizeof(int));
     if (ret < 0) {
          perror("reading token length");
          return -1;
     } else if (ret != 4) {
         if (display_file)
             fprintf(display_file,
                     "reading token length: %d of %d bytes read\n",
                     ret, 4);
         return -1;
     }

     tok->length = ntohl(len);
     tok->value = (char *) malloc(tok->length);
     if (tok->value == NULL) {
         if (display_file)
             fprintf(display_file,
                     "Out of memory allocating token data\n");
          return -1;
     }

     ret = read_all(s, (char *) tok->value, (OM_uint32)tok->length);
     if (ret < 0) {
          perror("reading token data");
          free(tok->value);
          return -1;
     } else if (ret != tok->length) {
          fprintf(stderr, "sending token data: %d of %d bytes written\n",
                  ret, tok->length);
          free(tok->value);
          return -1;
     }

     return 0;
}