# GSSAPIHandler.cc

Go to the documentation of this file.

    00001 // ----------------------------------------------------------------------------
    00002 // CERTI - HLA RunTime Infrastructure
    00003 // Copyright (C) 2002, 2003  ONERA
    00004 //
    00005 // This file is part of CERTI-libCERTI
    00006 //
    00007 // CERTI-libCERTI is free software ; you can redistribute it and/or
    00008 // modify it under the terms of the GNU Lesser General Public License
    00009 // as published by the Free Software Foundation ; either version 2 of
    00010 // the License, or (at your option) any later version.
    00011 //
    00012 // CERTI-libCERTI is distributed in the hope that it will be useful, but
    00013 // WITHOUT ANY WARRANTY ; without even the implied warranty of
    00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    00015 // Lesser General Public License for more details.
    00016 //
    00017 // You should have received a copy of the GNU Lesser General Public
    00018 // License along with this program ; if not, write to the Free Software
    00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
    00020 // USA
    00021 //
    00022 // $Id: GSSAPIHandler.cc,v 3.7 2008/12/07 20:16:14 gotthardp Exp $
    00023 // ----------------------------------------------------------------------------
    00024
    00025 #ifdef WITH_GSSAPI
    00026
    00027 #include "GSSAPIHandler.hh"
    00028 #include "PrettyDebug.hh"
    00029 #include "SocketTCP.hh"
    00030
    00031 namespace certi {
    00032
    00033 static pdCDebug D("HLAGSSAPI", "(H-GSSAPI) - ");
    00034
    00035 // ----------------------------------------------------------------------------
    00039 void GSSAPIHandler::acquireCred(int InitOrAccept)
    00040 {
    00041     D.Out(pdInit, "GSSAPI: Acquire Credential.");
    00042
    00043     Code = gss_acquire_cred(&Minor,
    00044                             LocalName, // Principal Name
    00045                             HLA_GSS_SESSION_DURATION, // Expiration delay
    00046                             GSS_C_NULL_OID_SET,
    00047                             InitOrAccept, // Cred. used to init.
    00048                             &Credential, // Returned Credential
    00049                             NULL,
    00050                             NULL);
    00051
    00052     detectError("GSSAPI: Acquire Credential");
    00053
    00054 }
    00055
    00056 // ----------------------------------------------------------------------------
    00061 void GSSAPIHandler::acceptSecContext(SocketTCP *Socket)
    00062 {
    00063     // The Input and Output Buffers used by the initial Handshake.
    00064
    00065     gss_buffer_desc InputToken = GSS_C_EMPTY_BUFFER ;
    00066     gss_buffer_desc OutputToken = GSS_C_EMPTY_BUFFER ;
    00067
    00068     int ReturnedFlags = 0 ;
    00069     OM_uint32 TimeRec = 0 ;
    00070
    00071     gss_cred_id_t DelegCredential ;
    00072
    00073     // Prevent Re-entrant calls
    00074
    00075     if (InitSecContext_Started == RTI_TRUE) {
    00076         D.Out(pdExcept, "GSSAPI: Reentrant call of GSSHandler::InitSecContext.");
    00077         printf("GSSAPI Fatal Error : Reentrant call in InitSecContext.\n");
    00078         throw NetworkError("Reentrant call of InitSecContext.");
    00079     }
    00080
    00081     InitSecContext_Started = RTI_TRUE ;
    00082     IsClient = RTI_FALSE ;
    00083
    00084     // Check Local Principal Name
    00085
    00086     if (LocalName == GSS_C_NO_NAME) {
    00087         printf("GSSAPI: Local Name must be set before accept_sec_ctxt.\n");
    00088         throw NetworkError("GSSAPI: Accept_Sec_Context: No name set.");
    00089     }
    00090
    00091
    00092     // Retrieve Credential
    00093
    00094     acquireCred(GSS_C_ACCEPT);
    00095
    00096
    00097     // Accept Security Context(Server Side)
    00098
    00099     do {
    00100
    00101         // Wait for peer's response if needed(InputToken may be allocated)
    00102
    00103         getToken(Socket, InputToken);
    00104
    00105         D.Out(pdInit, "GSSAPI: Received Security Context Token(%d bytes)",
    00106               InputToken.length);
    00107
    00108         // Accept Token
    00109
    00110         Code = gss_accept_sec_context(&Minor,
    00111                                       &Context, // Initially no context
    00112                                       Credential,
    00113                                       &InputToken, // Client Token
    00114                                       GSS_C_NO_CHANNEL_BINDINGS,
    00115                                       &RemoteName, // Client Name or NULL
    00116                                       &MechType,
    00117                                       &OutputToken,
    00118                                       &ReturnedFlags,
    00119                                       &TimeRec,
    00120                                       &DelegCredential);
    00121
    00122         detectError("GSSAPI: Accept Security Context");
    00123
    00124         // If the Credential was delegated, print a warning.
    00125
    00126         if (DelegCredential != GSS_C_NO_CREDENTIAL) {
    00127             printf("GSSAPI: Warning : Client has delegated his credential.\n");
    00128             gss_release_cred(&Minor, &DelegCredential);
    00129         }
    00130
    00131         // If a service was requested but is not available, print a warning.
    00132
    00133         if (HLA_GSS_FLAGS & !ReturnedFlags) {
    00134             printf("GSSAPI: Some unavailable service was requested.\n");
    00135             printf("GSSAPI: Returned service flags are : 0x%X\n", ReturnedFlags);
    00136         }
    00137
    00138         D.Out(pdInit, "GSSAPI: Security Context accepted.");
    00139
    00140         // Free Input Token
    00141
    00142         if (InputToken.value != NULL)
    00143             free(InputToken.value);
    00144
    00145         InputToken.length = 0 ;
    00146         InputToken.value = NULL ;
    00147
    00148         // Send Output token to peer and then release it.
    00149
    00150         if (OutputToken.length > 0) {
    00151
    00152             D.Out(pdInit,
    00153                   "GSSAPI: Accept Sec Context sending answer Token(%d bytes).",
    00154                   OutputToken.length);
    00155
    00156             sendToken(Socket, OutputToken);
    00157
    00158             gss_release_buffer(&Minor, &OutputToken);
    00159
    00160             OutputToken.length = 0 ;
    00161             OutputToken.value = NULL ;
    00162         }
    00163
    00164     } while (Code != GSS_S_COMPLETE); // Loop until no response is needed
    00165
    00166 }
    00167
    00168 // ----------------------------------------------------------------------------
    00170 GSSAPIHandler::GSSAPIHandler()
    00171 {
    00172     InitSecContext_Started = RTI_FALSE ;
    00173
    00174     LocalName = GSS_C_NO_NAME ;
    00175     RemoteName = GSS_C_NO_NAME ;
    00176
    00177     Credential = GSS_C_NO_CREDENTIAL ;
    00178     Context = GSS_C_NO_CONTEXT ;
    00179
    00180     MechType = GSS_C_NULL_OID ;
    00181
    00182     IsClient = RTI_FALSE ; // Reset by Init and Accept Sec. Context
    00183 }
    00184
    00185 // ----------------------------------------------------------------------------
    00187 GSSAPIHandler::~GSSAPIHandler()
    00188 {
    00189     D.Out(pdTerm, "GSSAPI: Releasing GSSAPI objects.");
    00190
    00191     // Release Names
    00192
    00193     if (LocalName != GSS_C_NO_NAME) {
    00194         gss_release_name(&Minor, &LocalName);
    00195         LocalName = GSS_C_NO_NAME ;
    00196     }
    00197
    00198     if (RemoteName != GSS_C_NO_NAME) {
    00199         gss_release_name(&Minor, &RemoteName);
    00200         RemoteName = GSS_C_NO_NAME ;
    00201     }
    00202
    00203     // Release Credential
    00204
    00205     if (Credential != GSS_C_NO_CREDENTIAL) {
    00206         gss_release_cred(&Minor, &Credential);
    00207         Credential = GSS_C_NO_CREDENTIAL ;
    00208     }
    00209
    00210     // Release Context(Client only)
    00211
    00212     if ((IsClient == RTI_TRUE) && (Context != GSS_C_NO_CONTEXT)) {
    00213
    00214         gss_delete_sec_context(&Minor, &Context, GSS_C_NO_BUFFER);
    00215
    00216         D.Out(pdTerm, "GSSAPI: Released Context.");
    00217
    00218         Context = GSS_C_NO_CONTEXT ;
    00219     }
    00220 }
    00221
    00222 // ----------------------------------------------------------------------------
    00226 void GSSAPIHandler::detectError(char *ContextString)
    00227 {
    00228     gss_buffer_desc ErrorMessage ;
    00229
    00230     if (GSS_ERROR(Code)) {
    00231
    00232         gss_display_status(&Minor, Code,
    00233                            GSS_C_GSS_CODE, GSS_MECH_DES,
    00234                            NULL, &ErrorMessage);
    00235
    00236         if (ContextString != NULL)
    00237             printf("%s: %s\n", ContextString, (char *)ErrorMessage.value);
    00238         else
    00239             printf("GSSAPI: %s\n", (char *)ErrorMessage.value);
    00240
    00241         gss_release_buffer(&Minor, &ErrorMessage);
    00242
    00243         throw NetworkError("Error in GSSAPI(see console output)");
    00244     }
    00245
    00246 }
    00247
    00248 // ----------------------------------------------------------------------------
    00252 void GSSAPIHandler::getMessage(SocketTCP *Socket,
    00253                                gss_buffer_t IncomingBuffer)
    00254 {
    00255     gss_buffer_desc SealedToken ;
    00256     gss_buffer_desc Signature ;
    00257
    00258     int ConfWasUsed ;
    00259     int QOPState ;
    00260
    00261     switch(RTI_GSSAPI_USAGE) {
    00262
    00263       case RTI_GSS_NOTHING:
    00264         // Get non-encrypted token.
    00265         getToken(Socket, SealedToken);
    00266
    00267         // 'Copy' non encrypted Token into Incoming Buffer(just change pointers)
    00268         IncomingBuffer->value = SealedToken.value ;
    00269         IncomingBuffer->length = SealedToken.length ;
    00270
    00271         // Don't free SealedToken ! IncomingBuffer will be freed by a call
    00272         // to GSSAPIHandler::ReleaseBuffer.
    00273         break ;
    00274
    00275       case RTI_GSS_SIGN_ONLY:
    00276         // Get Token(ie "Buffer Length" + "Buffer" + "Signature Token")
    00277         getToken(Socket, SealedToken);
    00278
    00279         // Get Buffer length
    00280         memcpy(& (IncomingBuffer->length), SealedToken.value, sizeof(OM_uint32));
    00281
    00282         // Get Buffer
    00283         IncomingBuffer->value
    00284             = (void *) calloc(IncomingBuffer->length, sizeof(char));
    00285
    00286         memcpy(IncomingBuffer->value,
    00287                (char *) SealedToken.value + sizeof(OM_uint32),
    00288                IncomingBuffer->length);
    00289
    00290         // Check Signature
    00291         Signature.value
    00292             = (char *)SealedToken.value + sizeof(OM_uint32) + IncomingBuffer->length ;
    00293         Signature.length
    00294             = SealedToken.length - sizeof(OM_uint32) - IncomingBuffer->length ;
    00295
    00296         Code = gss_verify(&Minor,
    00297                           Context,
    00298                           IncomingBuffer,
    00299                           &Signature,
    00300                           &QOPState);
    00301
    00302         detectError("GSSAPI: Get Message[verify]");
    00303
    00304         // Free memory
    00305         free(SealedToken.value);
    00306
    00307         break ;
    00308
    00309       case RTI_GSS_ENCRYPT:
    00310
    00311         // Get encrypted token.
    00312         getToken(Socket, SealedToken);
    00313
    00314         // Decrypt Token
    00315         Code = gss_unseal(&Minor,
    00316                           Context,
    00317                           &SealedToken,
    00318                           IncomingBuffer,
    00319                           &ConfWasUsed,
    00320                           &QOPState);
    00321
    00322         free(SealedToken.value);
    00323         break ;
    00324
    00325       default:
    00326         printf("BAD VALUE FOR RTI_GSSAPI_USAGE\n");
    00327         throw RTIinternalError();
    00328     }
    00329
    00330     detectError("GSSAPI: Get Message[unseal]");
    00331 }
    00332
    00333 // ----------------------------------------------------------------------------
    00339 char *GSSAPIHandler::getRemoteName()
    00340 {
    00341     gss_buffer_desc OutputName ;
    00342     gss_OID OutputNameType ;
    00343     char *Buffer ;
    00344
    00345     gss_display_name(&Minor,
    00346                      RemoteName,
    00347                      &OutputName,
    00348                      &OutputNameType);
    00349
    00350     detectError("GSSAPI: GetRemoteName");
    00351
    00352     // Copy OutputName into char buffer.
    00353
    00354     Buffer = (char *) malloc((OutputName.length + 1) * sizeof(char));
    00355     strncpy(Buffer, (char *) OutputName.value, OutputName.length);
    00356     Buffer[OutputName.length] = '\0' ;
    00357
    00358     releaseBuffer(&OutputName);
    00359
    00360     // Remove any '@'(network address part)
    00361
    00362     if (strchr(Buffer, '@') != NULL)
    00363         strchr(Buffer, '@')[0] = '\0' ;
    00364
    00365     D.Out(pdInit, "GSSAPI: Peer is %s.", Buffer);
    00366
    00367     return Buffer ;
    00368 }
    00369
    00370 // ----------------------------------------------------------------------------
    00378 void GSSAPIHandler::getToken(SocketTCP *Socket, gss_buffer_desc &Buffer)
    00379 {
    00380     // Read Token size.
    00381     Socket->SocketTCP::receive((void *) &Buffer.length,
    00382                                sizeof(Buffer.length));
    00383
    00384     // Allocate memory for content.
    00385     Buffer.value = (void *) calloc(Buffer.length, sizeof(char));
    00386
    00387     // Read content.
    00388     Socket->SocketTCP::receive((void *) Buffer.value,
    00389                                Buffer.length);
    00390 }
    00391
    00392 // ----------------------------------------------------------------------------
    00397 void GSSAPIHandler::initSecContext(SocketTCP *Socket)
    00398 {
    00399     // The Input and Output Buffers used by the initial Handshake.
    00400
    00401     gss_buffer_desc InputToken = GSS_C_EMPTY_BUFFER ;
    00402     gss_buffer_desc OutputToken = GSS_C_EMPTY_BUFFER ;
    00403
    00404     gss_buffer_t InputTokenPtr = GSS_C_NO_BUFFER ;
    00405
    00406     int ReturnedFlags = 0 ;
    00407     OM_uint32 ContextValidity = 0 ;
    00408
    00409     // Prevent Re-entrant calls
    00410
    00411     if (InitSecContext_Started == RTI_TRUE) {
    00412         D.Out(pdExcept, "GSSAPI: Reentrant call of GSSHandler::InitSecContext.");
    00413         printf("GSSAPI Fatal Error : Reentrant call in InitSecContext.\n");
    00414         throw NetworkError("Reentrant call of InitSecContext.");
    00415     }
    00416
    00417     InitSecContext_Started = RTI_TRUE ;
    00418     IsClient = RTI_TRUE ;
    00419
    00420     // Check Local and Remote Names
    00421
    00422     if ((LocalName == GSS_C_NO_NAME) || (RemoteName == GSS_C_NO_NAME)) {
    00423         printf("GSSAPI: Local/Remote Name must be set before init_sec_ctxt.\n");
    00424         throw NetworkError("GSSAPI: Init_Sec_Context: No name set.");
    00425     }
    00426
    00427
    00428     // Retrieve Credential
    00429
    00430     acquireCred(GSS_C_INITIATE);
    00431
    00432     D.Out(pdInit, "GSSAPI: Init Sec Context.");
    00433
    00434     // Get Security Context(Client Side)
    00435
    00436     do {
    00437
    00438         if (InputToken.length != 0)
    00439             InputTokenPtr = &InputToken ;
    00440         else
    00441             InputTokenPtr = GSS_C_NO_BUFFER ;
    00442
    00443         Code = gss_init_sec_context(&Minor,
    00444                                     Credential,
    00445                                     &Context,
    00446                                     RemoteName,
    00447                                     GSS_C_NULL_OID,
    00448                                     HLA_GSS_FLAGS, // See RTIconfig.hh
    00449                                     HLA_GSS_SESSION_DURATION, // See RTIconfig.hh
    00450                                     GSS_C_NO_CHANNEL_BINDINGS,
    00451                                     InputTokenPtr,
    00452                                     &MechType,
    00453                                     &OutputToken,
    00454                                     &ReturnedFlags,
    00455                                     &ContextValidity);
    00456
    00457         detectError("GSSAPI: Init Security Context");
    00458
    00459         // If a service was requested but is not available, print a warning.
    00460
    00461         if (HLA_GSS_FLAGS & !ReturnedFlags) {
    00462             printf("GSSAPI: Some unavailable service was requested.\n");
    00463             printf("GSSAPI: Returned service flags are : 0x%X\n", ReturnedFlags);
    00464         }
    00465
    00466         D.Out(pdInit, "GSSAPI: Security Context initiated(Validity: %d).",
    00467               ContextValidity);
    00468
    00469         // Free Input Token(allocated in a previous loop)
    00470
    00471         if (InputToken.value != NULL)
    00472             free(InputToken.value);
    00473
    00474         InputToken.length = 0 ;
    00475         InputToken.value = NULL ;
    00476
    00477         // Send Output token to peer and then release it.
    00478
    00479         if (OutputToken.length > 0) {
    00480
    00481             D.Out(pdInit, "GSSAPI: Init Sec Context sending Token(%d bytes).",
    00482                   OutputToken.length);
    00483
    00484             sendToken(Socket, OutputToken);
    00485
    00486             gss_release_buffer(&Minor, &OutputToken);
    00487
    00488             OutputToken.length = 0 ;
    00489             OutputToken.value = NULL ;
    00490         }
    00491
    00492         // Wait for peer's response if needed(InputToken may be allocated)
    00493
    00494         if (Code==GSS_S_CONTINUE_NEEDED) {
    00495
    00496             D.Out(pdInit, "GSSAPI: Init Sec Context waiting for server answer...");
    00497
    00498             getToken(Socket, InputToken);
    00499         }
    00500
    00501     } while (Code != GSS_S_COMPLETE); // Loop until no response is needed
    00502
    00503 }
    00504
    00505 // ----------------------------------------------------------------------------
    00509 void GSSAPIHandler::releaseBuffer(gss_buffer_t IncomingBuffer)
    00510 {
    00511     switch(RTI_GSSAPI_USAGE) {
    00512
    00513       case RTI_GSS_NOTHING:
    00514       case RTI_GSS_SIGN_ONLY:
    00515         // Buffer was allocated by GetToken
    00516         free(IncomingBuffer->value);
    00517         IncomingBuffer->value = NULL ;
    00518         IncomingBuffer->length = 0 ;
    00519         break ;
    00520
    00521       case RTI_GSS_ENCRYPT:
    00522         gss_release_buffer(&Minor, IncomingBuffer);
    00523     }
    00524 }
    00525
    00526 // ----------------------------------------------------------------------------
    00528 void
    00529 GSSAPIHandler::sendMessage(SocketTCP *Socket,
    00530                            gss_buffer_t OutcomingBuffer)
    00531 {
    00532     gss_buffer_desc SealedToken ;
    00533     gss_buffer_desc SignatureToken ;
    00534
    00535     OM_uint32 OutLength = OutcomingBuffer->length ;
    00536     void *OutValue = OutcomingBuffer->value ;
    00537     int ConfState ;
    00538
    00539     detectError("GSSAPI: Seal Message");
    00540
    00541     switch(RTI_GSSAPI_USAGE) {
    00542
    00543       case RTI_GSS_NOTHING:
    00544         // Send clear-text message.
    00545         sendToken(Socket, *OutcomingBuffer);
    00546         break ;
    00547
    00548       case RTI_GSS_SIGN_ONLY:
    00549         // Compute Signature Token
    00550         Code = gss_sign(&Minor,
    00551                         Context,
    00552                         GSS_C_QOP_DEFAULT,
    00553                         OutcomingBuffer,
    00554                         &SignatureToken);
    00555
    00556         detectError("GSSAPI: Send Message[sign]");
    00557
    00558         // Compute SealedToken : "Buffer Length" + "Buffer" + "Signature Token"
    00559         SealedToken.length = sizeof(OM_uint32);
    00560         SealedToken.length += OutLength ;
    00561         SealedToken.length += SignatureToken.length ;
    00562
    00563         SealedToken.value = (void *) calloc(SealedToken.length, sizeof(char));
    00564
    00565         // Copy OutcomingBuffer length
    00566         memcpy(SealedToken.value, & (OutLength), sizeof(OM_uint32));
    00567
    00568         // Copy OutcomingBuffer
    00569         memcpy((char *) SealedToken.value + sizeof(OM_uint32),
    00570                OutValue, OutLength);
    00571
    00572         // Copy SignatureToken
    00573         memcpy((char *) SealedToken.value + sizeof(OM_uint32) + OutLength,
    00574                SignatureToken.value, SignatureToken.length);
    00575
    00576         // Send resulting Token
    00577         sendToken(Socket, SealedToken);
    00578
    00579         // Free memory
    00580         free(SealedToken.value);
    00581         gss_release_buffer(&Minor, &SignatureToken);
    00582
    00583         break ;
    00584
    00585       case RTI_GSS_ENCRYPT:
    00586
    00587         Code = gss_seal(&Minor,
    00588                         Context,
    00589                         RTI_TRUE,
    00590                         GSS_C_QOP_DEFAULT,
    00591                         OutcomingBuffer,
    00592                         &ConfState,
    00593                         &SealedToken);
    00594
    00595         detectError("GSSAPI: Send Message[seal]");
    00596
    00597         sendToken(Socket, SealedToken);
    00598         gss_release_buffer(&Minor, &SealedToken);
    00599     }
    00600
    00601 }
    00602
    00603 // ----------------------------------------------------------------------------
    00611 void GSSAPIHandler::sendToken(SocketTCP *Socket, gss_buffer_desc Buffer)
    00612 {
    00613     // Write Token Length
    00614     Socket->SocketTCP::send((void *) &Buffer.length,
    00615                             sizeof(Buffer.length));
    00616
    00617     // Write Token Content
    00618     Socket->SocketTCP::send((void *) Buffer.value,
    00619                             Buffer.length);
    00620 }
    00621
    00622 // ----------------------------------------------------------------------------
    00624 void GSSAPIHandler::setLocalName(char *PrincipalName)
    00625 {
    00626     char *p ;
    00627     char bidon[80] ;
    00628
    00629     gss_buffer_desc LocalBuffer = GSS_C_EMPTY_BUFFER ;
    00630
    00631     strcpy(bidon, PrincipalName);
    00632
    00633     // Put Principal Name in GSSAPI buffer
    00634
    00635     if ((PrincipalName == NULL) || (strlen(PrincipalName) == 0))
    00636         throw NetworkError("Bad Local Principal Name.");
    00637
    00638     // Remove any machine name(like in rtip@jocaste)
    00639     p = strchr(bidon, '@');
    00640     if (p != NULL) {
    00641         *p = '\0' ;
    00642     }
    00643
    00644     LocalBuffer.value = bidon ;
    00645     LocalBuffer.length = strlen(bidon) + 1 ;
    00646
    00647     // Give Name to GSSAPI
    00648
    00649     Code = gss_import_name(&Minor,
    00650                            (gss_buffer_t) &LocalBuffer,
    00651                            GSS_C_NULL_OID,
    00652                            &LocalName);
    00653
    00654     D.Out(pdInit, "GSSAPI: Local Name set to %s.", bidon);
    00655
    00656     detectError("GSSAPI/setLocalName");
    00657 }
    00658
    00659 // ----------------------------------------------------------------------------
    00661
    00663 void GSSAPIHandler::setRemoteName(char *PrincipalName)
    00664 {
    00665     gss_buffer_desc LocalBuffer = GSS_C_EMPTY_BUFFER ;
    00666
    00667     // Put Principal Name in GSSAPI buffer
    00668
    00669     if ((PrincipalName == NULL) || (strlen(PrincipalName) == 0))
    00670         throw NetworkError("Bad Local Principal Name.");
    00671
    00672     LocalBuffer.value = PrincipalName ;
    00673     LocalBuffer.length = strlen(PrincipalName) + 1 ;
    00674
    00675     // Give Name to GSSAPI
    00676
    00677     Code = gss_import_name(&Minor,
    00678                            (gss_buffer_t) &LocalBuffer,
    00679                            GSS_C_NULL_OID,
    00680                            &RemoteName);
    00681
    00682     D.Out(pdInit, "GSSAPI: Remote Name set to %s.", PrincipalName);
    00683
    00684     detectError("GSSAPI/setRemoteName");
    00685 }
    00686
    00687 }
    00688
    00689 #endif // WITH_GSSAPI
    00690
    00691 // $Id: GSSAPIHandler.cc,v 3.7 2008/12/07 20:16:14 gotthardp Exp $