Solaris 开发者安全性指南

接受上下文

建立上下文通常涉及到在客户机和服务器之间执行一系列令牌交换。为了保持程序的可移植性,应当在循环中同时执行上下文接受和上下文初始化。用于接受上下文的循环与用于建立上下文的循环非常相似,但是二者的方向相反。请与建立与服务器的安全上下文进行比较。

以下源代码说明了 server_establish_context() 函数。


注 –

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



示例 6–4 server_establish_context() 函数

/*

 * Function: server_establish_context

 *

 * Purpose: establishes a GSS-API context as a specified service with

 * an incoming client, and returns the context handle and associated

 * client name

 *

 * Arguments:

 *

 *      s               (r) an established TCP connection to the client

 *      service_creds   (r) server credentials, from gss_acquire_cred

 *      context         (w) the established GSS-API context

 *      client_name     (w) the client's ASCII name

 *

 * Returns: 0 on success, -1 on failure

 *

 * Effects:

 *

 * Any valid client request is accepted.  If a context is established,

 * its handle is returned in context and the client name is returned

 * in client_name and 0 is returned.  If unsuccessful, an error

 * message is displayed and -1 is returned.

 */

int server_establish_context(s, server_creds, context, client_name, ret_flags)

     int s;

     gss_cred_id_t server_creds;

     gss_ctx_id_t *context;

     gss_buffer_t client_name;

     OM_uint32 *ret_flags;

{

     gss_buffer_desc send_tok, recv_tok;

     gss_name_t client;

     gss_OID doid;

     OM_uint32 maj_stat, min_stat, acc_sec_min_stat;

     gss_buffer_desc    oid_name;



     *context = GSS_C_NO_CONTEXT;

     

     do {

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

               return -1;



          if (verbose && log) {

              fprintf(log, "Received token (size=%d): \n", recv_tok.length);

              print_token(&recv_tok);

          }



          maj_stat =

               gss_accept_sec_context(&acc_sec_min_stat,

                                      context,

                                      server_creds,

                                      &recv_tok,

                                      GSS_C_NO_CHANNEL_BINDINGS,

                                      &client,

                                      &doid,

                                      &send_tok,

                                      ret_flags,

                                      NULL,     /* ignore time_rec */

                                      NULL);    /* ignore del_cred_handle */



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



          if (send_tok.length != 0) {

              if (verbose && log) {

                  fprintf(log,

                          "Sending accept_sec_context token (size=%d):\n",

                          send_tok.length);

                  print_token(&send_tok);

              }

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

                    fprintf(log, "failure sending token\n");

                    return -1;

               }



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

          }

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

               display_status("accepting context", maj_stat,

                              acc_sec_min_stat);

               if (*context == GSS_C_NO_CONTEXT)

                       gss_delete_sec_context(&min_stat, context,

                                              GSS_C_NO_BUFFER);

               return -1;

          }



          if (verbose && log) {

              if (maj_stat == GSS_S_CONTINUE_NEEDED)

                  fprintf(log, "continue needed...\n");

              else

                  fprintf(log, "\n");

              fflush(log);

          }

     } while (maj_stat == GSS_S_CONTINUE_NEEDED);



     /* display the flags */

     display_ctx_flags(*ret_flags);



     if (verbose && log) {

         maj_stat = gss_oid_to_str(&min_stat, doid, &oid_name);

         if (maj_stat != GSS_S_COMPLETE) {

             display_status("converting oid->string", maj_stat, min_stat);

             return -1;

         }

         fprintf(log, "Accepted connection using mechanism OID %.*s.\n",

                 (int) oid_name.length, (char *) oid_name.value);

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

     }



     maj_stat = gss_display_name(&min_stat, client, client_name, &doid);

     if (maj_stat != GSS_S_COMPLETE) {

          display_status("displaying name", maj_stat, min_stat);

          return -1;

     }

     maj_stat = gss_release_name(&min_stat, &client);

     if (maj_stat != GSS_S_COMPLETE) {

          display_status("releasing name", maj_stat, min_stat);

          return -1;

     }

     return 0;

}

sign_server() 函数使用以下源代码,通过调用 server_establish_context() 来接受上下文。

/* Establish a context with the client */

     if (server_establish_context(s, server_creds, &context,

				  &client_name, &ret_flags) < 0)

	return(-1);

server_establish_context() 函数首先查找客户机在初始化上下文的过程中发送的令牌。由于 GSS-API 本身不会收发令牌,因此程序必须各自具有用于执行这些任务的例程。服务器使用 recv_token() 来接收令牌:

     do {

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

               return -1;

接下来,server_establish_context() 会调用 GSS-API 函数 gss_accept_sec_context()

     maj_stat = gss_accept_sec_context(&min_stat,

                                      context,

                                      server_creds,

                                      &recv_tok,

                                      GSS_C_NO_CHANNEL_BINDINGS,

                                      &client,

                                      &doid,

                                      &send_tok,

                                      ret_flags,

                                      NULL,     /* ignore time_rec */

                                      NULL);    /* ignore del_cred_handle */

只要 gss_accept_sec_context()maj_stat 设置为 GSS_S_CONTINUE_NEEDED,接受循环就将继续并且不会遇到任何错误。如果 maj_stat 与该值或者 GSS_S_COMPLETE 不等,则表明存在问题,循环将退出。

无论是否存在要发送回客户机的令牌,gss_accept_sec_context() 都会返回一个表示 send_tok 长度的正值。下一步是查看是否存在要发送的令牌,如果存在,则发送该令牌:

     if (send_tok.length != 0) {

          . . .

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

               fprintf(log, "failure sending token\n");

               return -1;

          }



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

          }