Solaris 开发者安全性指南

为 GSS-API 建立安全上下文

将服务转换为 GSS-API 内部格式之后即可建立上下文。 为了尽可能提高可移植性,应当始终循环建立上下文。

进入循环之前,client_establish_context() 会初始化上下文和 token_ptr 参数。 使用 token_ptr 时需要进行选择。 token_ptr 可以指向 send_tok(发送到服务器的令牌)或 recv_tok(服务器发回的令牌)。

在循环内部,需要检查两项:

以下伪代码对该循环进行了说明:

do

     gss_init_sec_context()

     if no context was created

         exit with error;

    if the status is neither "complete" nor "in process"

          release the service namespace and exit with error;

    if there is a token to send to the server, that is, the size is nonzero

          send the token;

         if sending the token  fails,

               release the token and service namespaces. Exit with error;

         release the namespace for the token that was just sent;

     if  the context is not completely set up

          receive a token from the server;

while the context is not complete

该循环从调用 gss_init_sec_context() 开始,该函数使用以下参数:


注 –

客户机在启动上下文之前无需获取凭证。 在客户端,凭证管理通过 GSS-API 以透明方式处理。即,GSS-API 知道如何获取此机制为该主体创建的凭证。因此,应用程序可以向 gss_init_sec_context() 传递缺省凭证。但是在服务器端,服务器应用程序在接受上下文之前必须明确获取服务的凭证。请参见获取凭证


检查了上下文或其一部分是否存在,以及 gss_init_sec_context() 是否返回有效状态之后,connect_to_server() 会检查 gss_init_sec_context() 是否提供了要发送到服务器的令牌。如果不存在任何令牌,则表明服务器已经指示不需要其他任何令牌。如果提供了令牌,则必须将该令牌发送到服务器。如果发送该令牌失败,则无法确定该令牌和服务的名称空间,并且 connect_to_server() 将退出。以下算法通过查看令牌的长度来检查令牌是否存在:

if (send_tok_length != 0) {

               if (send_token(s, &send_tok) < 0) {

                    (void) gss_release_buffer(&min_stat, &send_tok);

                    (void) gss_release_name(&min_stat, &target_name);

                    return -1;

               }

          }

send_token() 不是 GSS-API 函数,需要由用户进行编写。send_token() 函数可将令牌写入到文件描述符中。send_token() 在成功时返回 0,在失败时返回 –1。GSS-API 本身不收发令牌。调用应用程序负责收发 GSS-API 已创建的任何令牌。

下面提供了用于建立上下文循环的源代码。


注 –

此示例的源代码也可以通过 Sun 下载中心获取。请访问 http://www.sun.com/download/products.xml?id=41912db5



示例 5–4 用于建立上下文的循环

/*

 * Perform the context establishment loop.

 *

 * On each pass through the loop, token_ptr points to the token

 * to send to the server (or GSS_C_NO_BUFFER on the first pass).

 * Every generated token is stored in send_tok which is then

 * transmitted to the server; every received token is stored in

 * recv_tok, which token_ptr is then set to, to be processed by

 * the next call to gss_init_sec_context.

 *

 * GSS-API guarantees that send_tok's length will be non-zero

 * if and only if the server is expecting another token from us,

 * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if

 * and only if the server has another token to send us.

 */



token_ptr = GSS_C_NO_BUFFER;

*gss_context = GSS_C_NO_CONTEXT;

1234567890123456789012345678901234567890123456789012345678901234567890123456



do {

    maj_stat =

        gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, 

        gss_context, target_name, oid, 

        GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | deleg_flag,

        0, NULL,                      /* no channel bindings */

        token_ptr, NULL,              /* ignore mech type */

        &send_tok, ret_flags, NULL);  /* ignore time_rec */

    if (gss_context == NULL){

        printf("Cannot create context\n");

        return GSS_S_NO_CONTEXT;

    }

    if (token_ptr != GSS_C_NO_BUFFER)

        (void) gss_release_buffer(&min_stat, &recv_tok);

    if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {

        display_status("initializing context", maj_stat, min_stat);

        (void) gss_release_name(&min_stat, &target_name);

        return -1;

    }



    if (send_tok.length != 0){

        fprintf(stdout, "Sending init_sec_context token (size=%ld)...",

            send_tok.length);

        if (send_token(s, &send_tok) < 0) {

            (void) gss_release_buffer(&min_stat, &send_tok);

            (void) gss_release_name(&min_stat, &target_name);

            return -1;

        }

    }

    (void) gss_release_buffer(&min_stat, &send_tok);



    if (maj_stat == GSS_S_CONTINUE_NEEDED) {

        fprintf(stdout, "continue needed...");

        if (recv_token(s, &recv_tok) < 0) {

            (void) gss_release_name(&min_stat, &target_name);

            return -1;

        }

        token_ptr = &recv_tok;

    }

          printf("\n");

     } while (maj_stat == GSS_S_CONTINUE_NEEDED);

有关 send_token()recv_token() 工作方式的更多信息,请参见各种 GSS-API 样例函数