nfs-ganesha 1.4

Svc_auth_gss.c

Go to the documentation of this file.
00001 /*
00002   Copyright (c) 2000 The Regents of the University of Michigan.
00003   All rights reserved.
00004 
00005   Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
00006   All rights reserved, all wrongs reversed.
00007 
00008   Redistribution and use in source and binary forms, with or without
00009   modification, are permitted provided that the following conditions
00010   are met:
00011 
00012   1. Redistributions of source code must retain the above copyright
00013      notice, this list of conditions and the following disclaimer.
00014   2. Redistributions in binary form must reproduce the above copyright
00015      notice, this list of conditions and the following disclaimer in the
00016      documentation and/or other materials provided with the distribution.
00017   3. Neither the name of the University nor the names of its
00018      contributors may be used to endorse or promote products derived
00019      from this software without specific prior written permission.
00020 
00021   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024   DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00025   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
00028   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 
00033   Id: svc_auth_gss.c,v 1.28 2002/10/15 21:29:36 kwc Exp
00034  */
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038 
00039 #ifdef _SOLARIS
00040 #include "solaris_port.h"
00041 #endif
00042 
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include "ganesha_rpc.h"
00047 #include "rpcal.h"
00048 #ifdef HAVE_HEIMDAL
00049 #include <gssapi.h>
00050 #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
00051 #else
00052 #include <gssapi/gssapi.h>
00053 #include <gssapi/gssapi_generic.h>
00054 #endif
00055 
00056 #include "nfs_core.h"
00057 #include "log.h"
00058 
00059 #ifdef SPKM
00060 
00061 #ifndef OID_EQ
00062 #define g_OID_equal(o1,o2) \
00063    (((o1)->length == (o2)->length) && \
00064     ((o1)->elements != 0) && ((o2)->elements != 0) && \
00065     (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0))
00066 #define OID_EQ 1
00067 #endif                          /* OID_EQ */
00068 
00069 extern const gss_OID_desc *const gss_mech_spkm3;
00070 
00071 #endif                          /* SPKM */
00072 
00073 #ifndef SVCAUTH_DESTROY
00074 #define SVCAUTH_DESTROY(auth) \
00075      ((*((auth)->svc_ah_ops->svc_ah_destroy))(auth))
00076 #endif
00077 
00078 extern SVCAUTH Svc_auth_none;
00079 
00080 #ifdef _USE_TIRPC
00081 static bool_t Svcauth_gss_destroy();
00082 static bool_t Svcauth_gss_destroy_copy();
00083 static bool_t Svcauth_gss_wrap();
00084 static bool_t Svcauth_gss_unwrap();
00085 #else
00086 static bool_t Svcauth_gss_destroy(SVCAUTH *);
00087 static bool_t Svcauth_gss_destroy_copy(SVCAUTH *);
00088 static bool_t Svcauth_gss_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
00089 static bool_t Svcauth_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);
00090 #endif
00091 
00092 static bool_t Svcauth_gss_nextverf(struct svc_req *, u_int);
00093 
00094 struct svc_auth_ops Svc_auth_gss_ops = {
00095   Svcauth_gss_wrap,
00096   Svcauth_gss_unwrap,
00097   Svcauth_gss_destroy
00098 };
00099 
00100 struct svc_auth_ops Svc_auth_gss_copy_ops = {
00101   Svcauth_gss_wrap,
00102   Svcauth_gss_unwrap,
00103   Svcauth_gss_destroy_copy
00104 };
00105 
00106 const char *str_gc_proc(rpc_gss_proc_t gc_proc)
00107 {
00108   switch(gc_proc)
00109    {
00110      case RPCSEC_GSS_DATA: return "RPCSEC_GSS_DATA";
00111      case RPCSEC_GSS_INIT: return "RPCSEC_GSS_INIT";
00112      case RPCSEC_GSS_CONTINUE_INIT: return "RPCSEC_GSS_CONTINUE_INIT";
00113      case RPCSEC_GSS_DESTROY: return "RPCSEC_GSS_DESTROY";
00114    }
00115 
00116  return "unknown";
00117 }
00118 
00131 void log_sperror_gss(char *outmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
00132 {
00133   OM_uint32 smin;
00134   gss_buffer_desc msg;
00135   gss_buffer_desc msg2;
00136   int msg_ctx = 0;
00137 
00138   if(gss_display_status(&smin,
00139                         maj_stat,
00140                         GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg) != GSS_S_COMPLETE)
00141     {
00142       sprintf(outmsg, "untranslatable error");
00143       return;
00144     }
00145 
00146   if(gss_display_status(&smin,
00147                         min_stat,
00148                         GSS_C_MECH_CODE,
00149                         GSS_C_NULL_OID, &msg_ctx, &msg2) != GSS_S_COMPLETE)
00150     {
00151       gss_release_buffer(&smin, &msg);
00152       sprintf(outmsg, "%s : untranslatable error", (char *)msg.value);
00153       return;
00154     }
00155 
00156   sprintf(outmsg, "%s : %s ", (char *)msg.value, (char *)msg2.value);
00157 
00158   gss_release_buffer(&smin, &msg);
00159   gss_release_buffer(&smin, &msg2);
00160 }                               /* log_sperror_gss */
00161 
00162 /* Global server credentials. */
00163 gss_cred_id_t svcauth_gss_creds;
00164 static gss_name_t svcauth_gss_name = NULL;
00165 
00166 bool_t Svcauth_gss_set_svc_name(gss_name_t name)
00167 {
00168   OM_uint32 maj_stat, min_stat;
00169 
00170   if(svcauth_gss_name != NULL)
00171     {
00172       maj_stat = gss_release_name(&min_stat, &svcauth_gss_name);
00173 
00174       if(maj_stat != GSS_S_COMPLETE)
00175         {
00176           return (FALSE);
00177         }
00178       svcauth_gss_name = NULL;
00179     }
00180 
00181   if(svcauth_gss_name == GSS_C_NO_NAME)
00182     return (TRUE);
00183 
00184   maj_stat = gss_duplicate_name(&min_stat, name, &svcauth_gss_name);
00185 
00186   if(maj_stat != GSS_S_COMPLETE)
00187     {
00188       return (FALSE);
00189     }
00190 
00191   return (TRUE);
00192 }
00193 
00194 bool_t Svcauth_gss_import_name(char *service)
00195 {
00196   gss_name_t name;
00197   gss_buffer_desc namebuf;
00198   OM_uint32 maj_stat, min_stat;
00199 
00200   namebuf.value = service;
00201   namebuf.length = strlen(service);
00202 
00203   maj_stat = gss_import_name(&min_stat, &namebuf, (gss_OID) gss_nt_service_name, &name);
00204 
00205   if(maj_stat != GSS_S_COMPLETE)
00206     {
00207       return (FALSE);
00208     }
00209   if(Svcauth_gss_set_svc_name(name) != TRUE)
00210     {
00211       gss_release_name(&min_stat, &name);
00212       return (FALSE);
00213     }
00214 
00215   /* set_svc_name() creates a duplicate, we don't need this copy */
00216   gss_release_name(&min_stat, &name);
00217 
00218   return (TRUE);
00219 }
00220 
00221 bool_t Svcauth_gss_acquire_cred(void)
00222 {
00223   OM_uint32 maj_stat, min_stat;
00224 
00225   maj_stat = gss_acquire_cred(&min_stat, svcauth_gss_name, 0,
00226                               GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
00227                               &svcauth_gss_creds, NULL, NULL);
00228 
00229   if(maj_stat != GSS_S_COMPLETE)
00230     {
00231       return (FALSE);
00232     }
00233   return (TRUE);
00234 }
00235 
00236 static bool_t Svcauth_gss_release_cred(void)
00237 {
00238   OM_uint32 maj_stat, min_stat;
00239 
00240   maj_stat = gss_release_cred(&min_stat, &svcauth_gss_creds);
00241 
00242   if(maj_stat != GSS_S_COMPLETE)
00243     {
00244       return (FALSE);
00245     }
00246 
00247   svcauth_gss_creds = NULL;
00248 
00249   return (TRUE);
00250 }
00251 
00252 static bool_t
00253 Svcauth_gss_accept_sec_context(struct svc_req *rqst, struct rpc_gss_init_res *gr)
00254 {
00255   struct svc_rpc_gss_data *gd;
00256   struct rpc_gss_cred *gc;
00257   gss_buffer_desc recv_tok, seqbuf;
00258   gss_OID mech;
00259   OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq;
00260 
00261   gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
00262   gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
00263   memset(gr, 0, sizeof(*gr));
00264 
00265   /* Deserialize arguments. */
00266   memset(&recv_tok, 0, sizeof(recv_tok));
00267 
00268   if(!svc_getargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args, (caddr_t) & recv_tok))
00269     return (FALSE);
00270 
00271   gr->gr_major = gss_accept_sec_context(&gr->gr_minor,
00272                                         &gd->ctx,
00273                                         svcauth_gss_creds,
00274                                         &recv_tok,
00275                                         GSS_C_NO_CHANNEL_BINDINGS,
00276                                         &gd->client_name,
00277                                         &mech, &gr->gr_token, &ret_flags, NULL, NULL);
00278 
00279   svc_freeargs(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_args, (caddr_t) & recv_tok);
00280 
00281   if(gr->gr_major != GSS_S_COMPLETE && gr->gr_major != GSS_S_CONTINUE_NEEDED)
00282     {
00283       sockaddr_t addr;
00284       char ipstring[SOCK_NAME_MAX];
00285       copy_xprt_addr(&addr, rqst->rq_xprt);
00286       sprint_sockaddr(&addr, ipstring, sizeof(ipstring));
00287 
00288       LogWarn(COMPONENT_RPCSEC_GSS,
00289               "Bad authentication major=%u minor=%u addr=%s",
00290               gr->gr_major, gr->gr_minor, ipstring);
00291       gd->ctx = GSS_C_NO_CONTEXT;
00292       goto errout;
00293     }
00294   /*
00295    * ANDROS: krb5 mechglue returns ctx of size 8 - two pointers,
00296    * one to the mechanism oid, one to the internal_ctx_id
00297    */
00298   if((gr->gr_ctx.value = gsh_malloc(sizeof(gss_union_ctx_id_desc))) == NULL)
00299     {
00300       LogCrit(COMPONENT_RPCSEC_GSS,
00301               "svcauth_gss_accept_context: out of memory");
00302       goto errout;
00303     }
00304   memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc));
00305   gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc);
00306 
00307   /* gr->gr_win = 0x00000005; ANDROS: for debugging linux kernel version...  */
00308   gr->gr_win = sizeof(gd->seqmask) * 8;
00309 
00310   /* Save client info. */
00311   gd->sec.mech = mech;
00312   gd->sec.qop = GSS_C_QOP_DEFAULT;
00313   gd->sec.svc = gc->gc_svc;
00314   gd->seq = gc->gc_seq;
00315   gd->win = gr->gr_win;
00316 
00317   if(gr->gr_major == GSS_S_COMPLETE)
00318     {
00319 #ifdef SPKM
00320       /* spkm3: no src_name (anonymous) */
00321       if(!g_OID_equal(gss_mech_spkm3, mech))
00322         {
00323 #endif
00324           maj_stat = gss_display_name(&min_stat, gd->client_name,
00325                                       &gd->cname, &gd->sec.mech);
00326           LogFullDebug(COMPONENT_RPCSEC_GSS,
00327                        "cname.val: %s  cname.len: %d",
00328                        (char *)gd->cname.value, (int)gd->cname.length);
00329 #ifdef SPKM
00330         }
00331 #endif
00332       if(maj_stat != GSS_S_COMPLETE)
00333         {
00334         }
00335 #ifdef HAVE_HEIMDAL
00336 #else
00337       if(isFullDebug(COMPONENT_RPCSEC_GSS))
00338         {
00339           gss_buffer_desc mechname;
00340 
00341           gss_oid_to_str(&min_stat, mech, &mechname);
00342 
00343           gss_release_buffer(&min_stat, &mechname);
00344         }
00345 #endif
00346       seq = htonl(gr->gr_win);
00347       seqbuf.value = &seq;
00348       seqbuf.length = sizeof(seq);
00349 
00350       gss_release_buffer(&min_stat, &gd->checksum);
00351       LogFullDebug(COMPONENT_RPCSEC_GSS,
00352                    "gss_sign in sec_accept_context");
00353       maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, &seqbuf, &gd->checksum);
00354 
00355       if(maj_stat != GSS_S_COMPLETE)
00356         {
00357           goto errout;
00358         }
00359 
00360       rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
00361       rqst->rq_xprt->xp_verf.oa_base = gd->checksum.value;
00362       rqst->rq_xprt->xp_verf.oa_length = gd->checksum.length;
00363     }
00364   return (TRUE);
00365  errout:
00366   gss_release_buffer(&min_stat, &gr->gr_token);
00367   return (FALSE);
00368 }
00369 
00370 int sprint_ctx(char *buff, unsigned char *ctx, int len)
00371 {
00372   int i;
00373 
00374   if(ctx == NULL)
00375     return sprintf(buff, "<null>");
00376 
00377   LogFullDebug(COMPONENT_RPCSEC_GSS,
00378                "sprint_ctx len=%d", len);
00379 
00380   if (len > 16)
00381     len = 16;
00382 
00383   for(i = 0; i < len; i++)
00384     sprintf(buff + i * 2, "%02x", ctx[i]);
00385 
00386   return len * 2;
00387 }
00388 
00389 static bool_t
00390 Svcauth_gss_validate(struct svc_req *rqst, struct svc_rpc_gss_data *gd,
00391                      struct rpc_msg *msg)
00392 {
00393   struct opaque_auth *oa;
00394   gss_buffer_desc rpcbuf, checksum;
00395   OM_uint32 maj_stat, min_stat, qop_state;
00396   u_char rpchdr[128];
00397   int32_t *buf;
00398   char GssError[256];
00399 
00400   memset(rpchdr, 0, sizeof(rpchdr));
00401 
00402   /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */
00403   oa = &msg->rm_call.cb_cred;
00404 
00405   LogFullDebug(COMPONENT_RPCSEC_GSS,
00406                "Call to Svcauth_gss_validate --> xid=%u dir=%u rpcvers=%u "
00407                "prog=%u vers=%u proc=%u flavor=%u len=%u base=%p ckeck.len=%u "
00408                "check.val=%p",
00409                msg->rm_xid,
00410                msg->rm_direction,
00411                msg->rm_call.cb_rpcvers,
00412                msg->rm_call.cb_prog,
00413                msg->rm_call.cb_vers,
00414                msg->rm_call.cb_proc,
00415                oa->oa_flavor,
00416                oa->oa_length,
00417                oa->oa_base,
00418                msg->rm_call.cb_verf.oa_length,
00419                msg->rm_call.cb_verf.oa_base);
00420 
00421   if(oa->oa_length > MAX_AUTH_BYTES)
00422     {
00423       LogCrit(COMPONENT_RPCSEC_GSS,
00424               "Svcauth_gss_validate oa->oa_length (%u) > MAX_AUTH_BYTES (%u)",
00425               oa->oa_length, MAX_AUTH_BYTES);
00426       return (FALSE);
00427     }
00428   
00429   /* 8 XDR units from the IXDR macro calls. */
00430   if(sizeof(rpchdr) < (8 * BYTES_PER_XDR_UNIT +
00431      RNDUP(oa->oa_length)))
00432     {
00433       LogCrit(COMPONENT_RPCSEC_GSS,
00434               "Svcauth_gss_validate sizeof(rpchdr) (%d) < "
00435               "(8 * BYTES_PER_XDR_UNIT (%d) + RNDUP(oa->oa_length (%u))) (%d)",
00436               (int) sizeof(rpchdr),
00437               (int) (8 * BYTES_PER_XDR_UNIT),
00438               oa->oa_length,
00439               (int) (8 * BYTES_PER_XDR_UNIT + RNDUP(oa->oa_length)));
00440       return (FALSE);
00441     }
00442 
00443   buf = (int32_t *) (void *)rpchdr;
00444   IXDR_PUT_LONG(buf, msg->rm_xid);
00445   IXDR_PUT_ENUM(buf, msg->rm_direction);
00446   IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers);
00447   IXDR_PUT_LONG(buf, msg->rm_call.cb_prog);
00448   IXDR_PUT_LONG(buf, msg->rm_call.cb_vers);
00449   IXDR_PUT_LONG(buf, msg->rm_call.cb_proc);
00450   IXDR_PUT_ENUM(buf, oa->oa_flavor);
00451   IXDR_PUT_LONG(buf, oa->oa_length);
00452   if(oa->oa_length)
00453     {
00454       memcpy((caddr_t) buf, oa->oa_base, oa->oa_length);
00455       buf += RNDUP(oa->oa_length) / sizeof(int32_t);
00456     }
00457   rpcbuf.value = rpchdr;
00458   rpcbuf.length = (u_char *) buf - rpchdr;
00459 
00460   checksum.value = msg->rm_call.cb_verf.oa_base;
00461   checksum.length = msg->rm_call.cb_verf.oa_length;
00462 
00463   if(isFullDebug(COMPONENT_RPCSEC_GSS))
00464     {
00465       char ctx_str[64];
00466       sprint_ctx(ctx_str, (unsigned char *)gd->ctx,
00467                  sizeof(gss_union_ctx_id_desc));
00468       LogFullDebug(COMPONENT_RPCSEC_GSS,
00469                    "Svcauth_gss_validate context %s rpcbuf=%p:%u "
00470                    "checksum=%p:$%u)",
00471                    ctx_str, rpcbuf.value, (unsigned int) rpcbuf.length,
00472                    checksum.value, (unsigned int) checksum.length);
00473     }
00474 
00475   maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, &qop_state);
00476 
00477   if(maj_stat != GSS_S_COMPLETE)
00478     {
00479       log_sperror_gss(GssError, maj_stat, min_stat);
00480       LogCrit(COMPONENT_RPCSEC_GSS, "Error in gss_verify_mic: %s", GssError);
00481       return (FALSE);
00482     }
00483   return (TRUE);
00484 }
00485 
00486 static bool_t Svcauth_gss_nextverf(struct svc_req *rqst, u_int num)
00487 {
00488   struct svc_rpc_gss_data *gd;
00489   gss_buffer_desc signbuf;
00490   OM_uint32 maj_stat, min_stat;
00491 
00492   if(rqst->rq_xprt->xp_auth == NULL)
00493     return (FALSE);
00494 
00495   gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
00496 
00497   gss_release_buffer(&min_stat, &gd->checksum);
00498 
00499   signbuf.value = &num;
00500   signbuf.length = sizeof(num);
00501 
00502   maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, &signbuf,
00503                          &gd->checksum);
00504 
00505   if(maj_stat != GSS_S_COMPLETE)
00506     {
00507       return (FALSE);
00508     }
00509   rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS;
00510   rqst->rq_xprt->xp_verf.oa_base = (caddr_t) gd->checksum.value;
00511   rqst->rq_xprt->xp_verf.oa_length = (u_int) gd->checksum.length;
00512 
00513   return (TRUE);
00514 }
00515 
00516 #define ret_freegc(code) do { retstat = code; goto freegc; } while (0)
00517 
00518 enum auth_stat
00519 Gssrpc__svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg,
00520                     bool_t *no_dispatch)
00521 {
00522   enum auth_stat retstat;
00523   XDR xdrs;
00524   SVCAUTH *auth;
00525   struct svc_rpc_gss_data *gd;
00526   struct rpc_gss_cred *gc;
00527   struct rpc_gss_init_res gr;
00528   int call_stat, offset;
00529   OM_uint32 min_stat;
00530   gss_union_ctx_id_desc *gss_ctx_data;
00531   char ctx_str[64];
00532 
00533   /* Used to update the hashtable entries. 
00534    * These should not be used for purposes other than updating
00535    * hashtable entries. */
00536   bool_t *p_established = NULL;
00537   u_int *p_seqlast = NULL;
00538   uint32_t *p_seqmask = NULL;
00539 
00540   /* Initialize reply. */
00541   LogFullDebug(COMPONENT_RPCSEC_GSS, "Gssrpc__svcauth_gss called");
00542 
00543   /* Allocate and set up server auth handle. */
00544   if ((rqst->rq_xprt->xp_auth == NULL) ||
00545       (rqst->rq_xprt->xp_auth == &Svc_auth_none))
00546     {
00547       if((auth = gsh_calloc(1, sizeof(*auth))) == NULL)
00548         {
00549           LogCrit(COMPONENT_RPCSEC_GSS, "svcauth_gss: out_of_memory");
00550           return (AUTH_FAILED);
00551         }
00552       if((gd = gsh_calloc(1, sizeof(*gd))) == NULL)
00553         {
00554           LogCrit(COMPONENT_RPCSEC_GSS, "svcauth_gss: out_of_memory");
00555           gsh_free(auth);
00556           return (AUTH_FAILED);
00557         }
00558       auth->svc_ah_ops = &Svc_auth_gss_ops;
00559       auth->svc_ah_private = (void *)gd;
00560       rqst->rq_xprt->xp_auth = auth;
00561     }
00562   else
00563     gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
00564 
00565   /* Deserialize client credentials. */
00566   if(rqst->rq_cred.oa_length <= 0)
00567     return (AUTH_BADCRED);
00568 
00569   gc = (struct rpc_gss_cred *)rqst->rq_clntcred;
00570   memset(gc, 0, sizeof(*gc));
00571 
00572   xdrmem_create(&xdrs, rqst->rq_cred.oa_base, rqst->rq_cred.oa_length,
00573                 XDR_DECODE);
00574 
00575   if(!xdr_rpc_gss_cred(&xdrs, gc))
00576     {
00577       XDR_DESTROY(&xdrs);
00578       return (AUTH_BADCRED);
00579     }
00580   XDR_DESTROY(&xdrs);
00581 
00582   if(gc->gc_ctx.length != 0)
00583     gss_ctx_data = (gss_union_ctx_id_desc *)(gc->gc_ctx.value);
00584   else
00585     gss_ctx_data = NULL;
00586 
00587   if(isFullDebug(COMPONENT_RPCSEC_GSS))
00588     {
00589       sprint_ctx(ctx_str, (char *)gc->gc_ctx.value, gc->gc_ctx.length);
00590       LogFullDebug(COMPONENT_RPCSEC_GSS,
00591                    "Gssrpc__svcauth_gss gc_proc (%u) %s context %s",
00592                    gc->gc_proc, str_gc_proc(gc->gc_proc), ctx_str);
00593     }
00594 
00595   /* If we do not retrieve gss data from the cache, then this important
00596    * variables could not possibly be meaningful. */
00597   gd->seqlast = 0;
00598   gd->seqmask = 0;
00599   gd->established = 0;
00600 
00602   /* if( gd->established == 0 && gc->gc_proc == RPCSEC_GSS_DATA   )*/
00603   if(gc->gc_proc == RPCSEC_GSS_DATA || gc->gc_proc == RPCSEC_GSS_DESTROY)
00604     {
00605       if(isFullDebug(COMPONENT_RPCSEC_GSS))
00606         {
00607           LogFullDebug(COMPONENT_RPCSEC_GSS,
00608                        "Dump context hash table");
00609           Gss_ctx_Hash_Print();
00610         }
00611       
00612       LogFullDebug(COMPONENT_RPCSEC_GSS, "Getting gss data struct from "
00613                    "hashtable.");
00614       
00615       /* Fill in svc_rpc_gss_data from cache */
00616       if(!Gss_ctx_Hash_Get(gss_ctx_data,
00617                            gd,
00618                            &p_established,
00619                            &p_seqlast,
00620                            &p_seqmask))
00621         {
00622           LogCrit(COMPONENT_RPCSEC_GSS, "Could not find gss context ");
00623           ret_freegc(AUTH_REJECTEDCRED);
00624         }
00625       else
00626         {
00627           /* If you 'mount -o sec=krb5i' you will have gc->gc_proc > 
00628            * RPCSEC_GSS_SVN_NONE, but the negociation will have been made as
00629            * if option was -o sec=krb5, the value of sec.svc has to be updated
00630            * id the stored gd that we got fromn the hash */
00631           if(gc->gc_svc != gd->sec.svc)
00632             gd->sec.svc = gc->gc_svc;
00633         }
00634     }
00635 
00636   if(isFullDebug(COMPONENT_RPCSEC_GSS))
00637     {
00638       char ctx_str_2[64];
00639 
00640       sprint_ctx(ctx_str_2, (unsigned char *)gd->ctx, sizeof(gss_ctx_data));
00641       sprint_ctx(ctx_str, (unsigned char *)gc->gc_ctx.value, gc->gc_ctx.length);
00642 
00643       LogFullDebug(COMPONENT_RPCSEC_GSS,
00644                    "Call to Gssrpc__svcauth_gss ----> Client=%s length=%lu "
00645                    "(GD: established=%u ctx=%s) (RQ:sock=%u) "
00646                    "(GC: Proc=%u Svc=%u ctx=%s)",
00647                    (char *)gd->cname.value,
00648                    (long unsigned int)gd->cname.length,
00649                    gd->established,
00650                    ctx_str_2,
00651                    rqst->rq_xprt->xp_fd,
00652                    gc->gc_proc,
00653                    gc->gc_svc,
00654                    ctx_str);
00655     }
00656 
00657   retstat = AUTH_FAILED;
00658 
00659   /* Check version. */
00660   if(gc->gc_v != RPCSEC_GSS_VERSION)
00661     {
00662       LogDebug(COMPONENT_RPCSEC_GSS,
00663                "BAD AUTH: bad GSS version.");
00664       ret_freegc(AUTH_BADCRED);
00665     }
00666 
00667   /* Check RPCSEC_GSS service. */
00668   if((gc->gc_svc != RPCSEC_GSS_SVC_NONE) &&
00669      (gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY) &&
00670      (gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY))
00671     {
00672       LogDebug(COMPONENT_RPCSEC_GSS,
00673                "BAD AUTH: bad GSS service (krb5, krb5i, krb5p)");
00674       ret_freegc(AUTH_BADCRED);
00675     }
00676 
00677   /* Check sequence number. */
00678   if(gd->established)
00679     {
00680       /* Sequence should be less than the max sequence number */
00681       if(gc->gc_seq > MAXSEQ)
00682         {
00683           LogDebug(COMPONENT_RPCSEC_GSS,
00684                    "BAD AUTH: max sequence number exceeded.");
00685           ret_freegc(RPCSEC_GSS_CTXPROBLEM);
00686         }
00687 
00688       /* Check the difference between the current sequence number 
00689        * and the last sequence number. */
00690       LogFullDebug(COMPONENT_RPCSEC_GSS,
00691                    "seqlast: %d  seqnum: %d offset: %d seqwin: %d seqmask: %x",
00692                    gd->seqlast, gc->gc_seq, gd->seqlast - gc->gc_seq, gd->win,
00693                    gd->seqmask);
00694 
00695       if((offset = gd->seqlast - gc->gc_seq) < 0)
00696         {
00697           gd->seqlast = gc->gc_seq;
00698           offset = 0 - offset;
00699           gd->seqmask <<= offset;
00700           offset = 0;
00701         }
00702       else if((unsigned int)offset >= gd->win
00703               || (gd->seqmask & (1 << (unsigned int)offset)))
00704         {
00705           if ((unsigned int)offset >= gd->win)
00706             LogDebug(COMPONENT_RPCSEC_GSS,
00707                      "BAD AUTH: the current seqnum is lower "
00708                      "than seqlast by %d and out of the seq window of size %d.", offset, gd->win);
00709           else
00710             LogDebug(COMPONENT_RPCSEC_GSS,
00711                      "BAD AUTH: the current seqnum has already been used.");
00712 
00713           *no_dispatch = TRUE;
00714           ret_freegc(RPCSEC_GSS_CTXPROBLEM);
00715         }
00716       gd->seq = gc->gc_seq;
00717       gd->seqmask |= (1 << offset);
00718     }
00719 
00720   if(gd->established)
00721     {
00722       rqst->rq_clntname = (char *)gd->client_name;
00723 #ifndef _USE_TIRPC
00724       rqst->rq_svccred = (char *)gd->ctx;
00725 #else
00726       rqst->rq_svcname = (char *)gd->ctx;
00727 #endif
00728     }
00729 
00730   /* Handle RPCSEC_GSS control procedure. */
00731   switch (gc->gc_proc)
00732     {
00733 
00734     case RPCSEC_GSS_INIT:
00735       LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_INIT:");
00736     case RPCSEC_GSS_CONTINUE_INIT:
00737       LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_CONTINUE_INIT:");
00738       if(rqst->rq_proc != NULLPROC)
00739         {
00740           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: request proc != NULL "
00741                        "during INIT request");
00742           ret_freegc(AUTH_FAILED);        /* XXX ? */
00743         }
00744 
00745       if(!Svcauth_gss_acquire_cred())
00746         {
00747           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Can't acquire "
00748                        "credentials from RPC request.");
00749           ret_freegc(AUTH_FAILED);
00750         }
00751 
00752       if(!Svcauth_gss_accept_sec_context(rqst, &gr))
00753         {
00754           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Can't accept the "
00755                        "security context.");
00756           ret_freegc(AUTH_REJECTEDCRED);
00757         }
00758 
00759       if(!Svcauth_gss_nextverf(rqst, htonl(gr.gr_win)))
00760         {
00761           gss_release_buffer(&min_stat, &gr.gr_token);
00762           gsh_free(gr.gr_ctx.value);
00763           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification "
00764                        "failed");
00765           ret_freegc(AUTH_FAILED);
00766         }
00767       *no_dispatch = TRUE;
00768 
00769       if(isFullDebug(COMPONENT_RPCSEC_GSS))
00770         {
00771           sprint_ctx(ctx_str, (unsigned char *)gr.gr_ctx.value,
00772                      gr.gr_ctx.length);
00773           LogFullDebug(COMPONENT_RPCSEC_GSS,
00774                        "Call to Gssrpc__svcauth_gss ----> Client=%s "
00775                        "length=%lu (GD: established=%u) (RQ:sock=%u) "
00776                        "(GR: maj=%u min=%u ctx=%s)",
00777                        (char *)gd->cname.value,
00778                        (long unsigned int)gd->cname.length,
00779                        gd->established,
00780                        rqst->rq_xprt->xp_fd,
00781                        gr.gr_major,
00782                        gr.gr_minor,
00783                        ctx_str);
00784         }
00785 
00786       call_stat = svc_sendreply2(rqst->rq_xprt, rqst,
00787                                  (xdrproc_t)xdr_rpc_gss_init_res,
00788                                  (caddr_t) & gr);
00789 
00790       gss_release_buffer(&min_stat, &gr.gr_token);
00791       gss_release_buffer(&min_stat, &gd->checksum);
00792       gsh_free(gr.gr_ctx.value);
00793 
00794       if(!call_stat)
00795         {
00796           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: svc_sendreply failed.");
00797           ret_freegc(AUTH_FAILED);
00798         }
00799 
00800       if(gr.gr_major == GSS_S_COMPLETE)
00801         {
00802           gss_union_ctx_id_desc *gss_ctx_data2 =
00803               (gss_union_ctx_id_desc *)gd->ctx;
00804 
00805           gd->established = TRUE;
00806 
00807           /* Keep the gss context in a hash, gr.gr_ctx.value is used as key */
00808           (void) Gss_ctx_Hash_Set(gss_ctx_data2, gd);
00809         }
00810 
00811       break;
00812 
00813     case RPCSEC_GSS_DATA:
00814       LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_DATA:");
00815       if(!Svcauth_gss_validate(rqst, gd, msg))
00816         {
00817           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Couldn't validate "
00818                        "request.");
00819           ret_freegc(RPCSEC_GSS_CREDPROBLEM);
00820         }
00821 
00822       if(!Svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
00823         {
00824           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification "
00825                        "failed.");
00826           ret_freegc(AUTH_FAILED);
00827         }
00828 
00829       /* Update a few important values in the hashtable entry */
00830       if ( p_established != NULL)
00831         *p_established = gd->established;
00832       if ( p_seqlast != NULL)
00833         *p_seqlast = gd->seqlast;
00834       if (p_seqmask != NULL)
00835         *p_seqmask = gd->seqmask;
00836 
00837       break;
00838 
00839     case RPCSEC_GSS_DESTROY:
00840       LogFullDebug(COMPONENT_RPCSEC_GSS, "Reached RPCSEC_GSS_DESTROY:");
00841       if(rqst->rq_proc != NULLPROC)
00842         ret_freegc(AUTH_FAILED);        /* XXX ? */
00843 
00844       if(!Svcauth_gss_validate(rqst, gd, msg))
00845         ret_freegc(RPCSEC_GSS_CREDPROBLEM);
00846 
00847       if(!Svcauth_gss_nextverf(rqst, htonl(gc->gc_seq)))
00848         {
00849           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Checksum verification "
00850                        "failed.");
00851           ret_freegc(AUTH_FAILED);
00852         }
00853 
00854       *no_dispatch = TRUE;
00855 
00856       call_stat = svc_sendreply2(rqst->rq_xprt, rqst,
00857                                  (xdrproc_t)xdr_void,
00858                                  (caddr_t) NULL);
00859 
00860       if(!Gss_ctx_Hash_Del(gss_ctx_data))
00861         {
00862           LogCrit(COMPONENT_RPCSEC_GSS,
00863                   "Could not delete Gss Context from hash");
00864         }
00865       else
00866         LogFullDebug(COMPONENT_RPCSEC_GSS, "Gss_ctx_Hash_Del OK");
00867 
00868       if(!Svcauth_gss_release_cred())
00869         {
00870           LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Failed to release "
00871                        "credentials.");
00872           ret_freegc(AUTH_FAILED);
00873         }
00874 
00875       if(rqst->rq_xprt->xp_auth)
00876         SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth);
00877       rqst->rq_xprt->xp_auth = &Svc_auth_none;
00878 
00879       break;
00880 
00881     default:
00882       LogFullDebug(COMPONENT_RPCSEC_GSS, "BAD AUTH: Request is not INIT, "
00883                    "INIT_CONTINUE, DATA, OR DESTROY.");
00884       ret_freegc(AUTH_REJECTEDCRED);
00885       break;
00886     }
00887 
00888   LogFullDebug(COMPONENT_RPCSEC_GSS,
00889                "Call to Gssrpc__svcauth_gss - OK ---> (RQ:sock=%u)",
00890                rqst->rq_xprt->xp_fd);
00891 
00892   retstat = AUTH_OK;
00893  freegc:
00894   if(retstat != AUTH_OK)
00895     LogCrit(COMPONENT_RPCSEC_GSS,
00896             "Call to Gssrpc__svcauth_gss - FAILED ---> (RQ:sock=%u)",
00897             rqst->rq_xprt->xp_fd);
00898 
00899   xdr_free((xdrproc_t)xdr_rpc_gss_cred, gc);
00900   return (retstat);
00901 }
00902 
00903 static bool_t Svcauth_gss_destroy(SVCAUTH * auth)
00904 {
00905   struct svc_rpc_gss_data *gd;
00906   OM_uint32 min_stat;
00907 
00908   gd = SVCAUTH_PRIVATE(auth);
00909 
00910   gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER);
00911 
00912   gss_release_buffer(&min_stat, &gd->cname);
00913   gss_release_buffer(&min_stat, &gd->checksum);
00914 
00915   if(gd->client_name)
00916     gss_release_name(&min_stat, &gd->client_name);
00917 
00918   gsh_free(gd);
00919   gsh_free(auth);
00920 
00921   return (TRUE);
00922 }
00923 
00924 static bool_t Svcauth_gss_destroy_copy(SVCAUTH * auth)
00925 {
00926   /* svc_ah_private aka gd points to the same gd as the original, so no need
00927    * to free or destroy.
00928    * Just free the auth structure (pointer to ops and pointer to gd).
00929    */
00930   gsh_free(auth);
00931 
00932   return (TRUE);
00933 }
00934 
00935 #ifndef DONT_USE_WRAPUNWRAP
00936 #define RPC_SLACK_SPACE 1024
00937 
00938 bool_t
00939 Xdr_rpc_gss_buf(XDR *xdrs, gss_buffer_t buf, u_int maxsize)
00940 {
00941         bool_t xdr_stat;
00942         u_int tmplen;
00943 
00944         if (xdrs->x_op != XDR_DECODE) {
00945                 if (buf->length > UINT_MAX)
00946                         return FALSE;
00947                 else
00948                         tmplen = buf->length;
00949         }
00950         xdr_stat = xdr_bytes(xdrs, (char **)&buf->value, &tmplen, maxsize);
00951 
00952         if (xdr_stat && xdrs->x_op == XDR_DECODE)
00953                 buf->length = tmplen;
00954 
00955         LogFullDebug(COMPONENT_RPCSEC_GSS,
00956                      "Xdr_rpc_gss_buf: %s %s (%p:%d)",
00957                   (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode",
00958                   (xdr_stat == TRUE) ? "success" : "failure",
00959                   buf->value, (int)buf->length);
00960 
00961         return xdr_stat;
00962 }
00963 
00964 bool_t
00965 Xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
00966                       gss_ctx_id_t ctx, gss_qop_t qop,
00967                       rpc_gss_svc_t svc, u_int seq)
00968 {
00969         gss_buffer_desc databuf, wrapbuf;
00970         OM_uint32       maj_stat, min_stat;
00971         int             start, end, conf_state;
00972         bool_t          xdr_stat = FALSE;
00973         u_int           databuflen, maxwrapsz;
00974 
00975         /* Skip databody length. */
00976         start = XDR_GETPOS(xdrs);
00977         XDR_SETPOS(xdrs, start + 4);
00978 
00979         memset(&databuf, 0, sizeof(databuf));
00980         memset(&wrapbuf, 0, sizeof(wrapbuf));
00981 
00982         /* Marshal rpc_gss_data_t (sequence number + arguments). */
00983         if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
00984                 return (FALSE);
00985         end = XDR_GETPOS(xdrs);
00986 
00987         /* Set databuf to marshalled rpc_gss_data_t. */
00988         databuflen = end - start - 4;
00989         XDR_SETPOS(xdrs, start + 4);
00990         databuf.value = XDR_INLINE(xdrs, databuflen);
00991         databuf.length = databuflen;
00992 
00993         xdr_stat = FALSE;
00994 
00995         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
00996                 /* Marshal databody_integ length. */
00997                 XDR_SETPOS(xdrs, start);
00998                 if (!xdr_u_int(xdrs, (u_int *)&databuflen))
00999                         return (FALSE);
01000 
01001                 /* Checksum rpc_gss_data_t. */
01002                 maj_stat = gss_get_mic(&min_stat, ctx, qop,
01003                                        &databuf, &wrapbuf);
01004                 if (maj_stat != GSS_S_COMPLETE) {
01005                         LogFullDebug(COMPONENT_RPCSEC_GSS,"gss_get_mic failed");
01006                         return (FALSE);
01007                 }
01008                 /* Marshal checksum. */
01009                 XDR_SETPOS(xdrs, end);
01010                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
01011                 xdr_stat = Xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
01012                 gss_release_buffer(&min_stat, &wrapbuf);
01013         }
01014         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
01015                 /* Encrypt rpc_gss_data_t. */
01016                 maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
01017                                     &conf_state, &wrapbuf);
01018                 if (maj_stat != GSS_S_COMPLETE) {
01019                         LogFullDebug(COMPONENT_RPCSEC_GSS,"gss_wrap %d %d",
01020                                      maj_stat, min_stat);
01021                         return (FALSE);
01022                 }
01023                 /* Marshal databody_priv. */
01024                 XDR_SETPOS(xdrs, start);
01025                 maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE);
01026                 xdr_stat = Xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz);
01027                 gss_release_buffer(&min_stat, &wrapbuf);
01028         }
01029         return (xdr_stat);
01030 }
01031 
01032 bool_t
01033 Xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
01034                         gss_ctx_id_t ctx, gss_qop_t qop,
01035                         rpc_gss_svc_t svc, u_int seq)
01036 {
01037         XDR             tmpxdrs;
01038         gss_buffer_desc databuf, wrapbuf;
01039         OM_uint32       maj_stat, min_stat;
01040         u_int           seq_num, qop_state;
01041         int                     conf_state;
01042         bool_t          xdr_stat;
01043 
01044         if (xdr_func == (xdrproc_t)xdr_void || xdr_ptr == NULL)
01045                 return (TRUE);
01046 
01047         memset(&databuf, 0, sizeof(databuf));
01048         memset(&wrapbuf, 0, sizeof(wrapbuf));
01049 
01050         if (svc == RPCSEC_GSS_SVC_INTEGRITY) {
01051                 /* Decode databody_integ. */
01052                 if (!Xdr_rpc_gss_buf(xdrs, &databuf, (u_int)-1)) {
01053                         LogFullDebug(COMPONENT_RPCSEC_GSS,"xdr decode "
01054                                      "databody_integ failed");
01055                         return (FALSE);
01056                 }
01057                 /* Decode checksum. */
01058                 if (!Xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
01059 #if 0
01060                         gss_release_buffer(&min_stat, &databuf);
01061 #else
01062                         gsh_free(databuf.value);
01063 #endif
01064                         LogFullDebug(COMPONENT_RPCSEC_GSS,
01065                                      "xdr decode checksum failed");
01066                         return (FALSE);
01067                 }
01068                 /* Verify checksum and QOP. */
01069                 maj_stat = gss_verify_mic(&min_stat, ctx, &databuf,
01070                                           &wrapbuf, &qop_state);
01071 #if 0
01072                 gss_release_buffer(&min_stat, &wrapbuf);
01073 #else
01074                         gsh_free(wrapbuf.value);
01075 #endif
01076 
01077                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop) {
01078 #if 0
01079                         gss_release_buffer(&min_stat, &databuf);
01080 #else
01081                         gsh_free(databuf.value);
01082 #endif
01083                         LogFullDebug(COMPONENT_RPCSEC_GSS,
01084                                      "gss_verify_mic %d %d", maj_stat,
01085                                      min_stat);
01086                         return (FALSE);
01087                 }
01088         }
01089         else if (svc == RPCSEC_GSS_SVC_PRIVACY) {
01090                 /* Decode databody_priv. */
01091                 if (!Xdr_rpc_gss_buf(xdrs, &wrapbuf, (u_int)-1)) {
01092                         LogFullDebug(COMPONENT_RPCSEC_GSS,
01093                                      "xdr decode databody_priv failed");
01094                         return (FALSE);
01095                 }
01096                 /* Decrypt databody. */
01097                 maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
01098                                       &conf_state, &qop_state);
01099 
01100                 gss_release_buffer(&min_stat, &wrapbuf);
01101 
01102                 /* Verify encryption and QOP. */
01103                 if (maj_stat != GSS_S_COMPLETE || qop_state != qop ||
01104                         conf_state != TRUE) {
01105                         gss_release_buffer(&min_stat, &databuf);
01106                         LogFullDebug(COMPONENT_RPCSEC_GSS,
01107                                      "gss_unwrap %d %d", maj_stat, min_stat);
01108                         return (FALSE);
01109                 }
01110         }
01111         /* Decode rpc_gss_data_t (sequence number + arguments). */
01112         xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE);
01113         xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) &&
01114                     (*xdr_func)(&tmpxdrs, xdr_ptr));
01115         XDR_DESTROY(&tmpxdrs);
01116 #if 0
01117         gss_release_buffer(&min_stat, &databuf);
01118 #else
01119         gsh_free(databuf.value);
01120 #endif
01121 
01122         /* Verify sequence number. */
01123         if (xdr_stat == TRUE && seq_num != seq) {
01124                 LogFullDebug(COMPONENT_RPCSEC_GSS,
01125                              "wrong sequence number in databody");
01126                 return (FALSE);
01127         }
01128         return (xdr_stat);
01129 }
01130 
01131 bool_t
01132 Xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
01133                  gss_ctx_id_t ctx, gss_qop_t qop,
01134                  rpc_gss_svc_t svc, u_int seq)
01135 {
01136         bool_t rc;
01137         switch (xdrs->x_op) {
01138 
01139         case XDR_ENCODE:
01140                 rc = (Xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr,
01141                                               ctx, qop, svc, seq));
01142                 LogFullDebug(COMPONENT_RPCSEC_GSS,
01143                              "Xdr_rpc_gss_data ENCODE returns %d",
01144                              rc);
01145                 return rc;
01146         case XDR_DECODE:
01147                 rc = (Xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr,
01148                                                 ctx, qop,svc, seq));
01149                 LogFullDebug(COMPONENT_RPCSEC_GSS,
01150                              "Xdr_rpc_gss_data DECODE returns %d",
01151                              rc);
01152                 return rc;
01153         case XDR_FREE:
01154                 return (TRUE);
01155         }
01156         return (FALSE);
01157 }
01158 #endif
01159 
01160 static bool_t
01161 Svcauth_gss_wrap(SVCAUTH * auth, XDR * xdrs, xdrproc_t xdr_func,
01162                  caddr_t xdr_ptr)
01163 {
01164   struct svc_rpc_gss_data *gd;
01165 
01166   gd = SVCAUTH_PRIVATE(auth);
01167 
01168   if(!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE)
01169     {
01170       return ((*xdr_func) (xdrs, xdr_ptr));
01171     }
01172 #ifndef DONT_USE_WRAPUNWRAP
01173   return (Xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
01174                            gd->ctx, gd->sec.qop, gd->sec.svc, gd->seq));
01175 #else
01176   return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
01177                            gd->ctx, gd->sec.qop, gd->sec.svc, gd->seq));
01178 #endif
01179 }
01180 
01181 static bool_t
01182 Svcauth_gss_unwrap(SVCAUTH * auth, XDR * xdrs, xdrproc_t xdr_func,
01183                    caddr_t xdr_ptr)
01184 {
01185   struct svc_rpc_gss_data *gd;
01186 
01187   gd = SVCAUTH_PRIVATE(auth);
01188 
01189   if(!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE)
01190     {
01191       return ((*xdr_func) (xdrs, xdr_ptr));
01192     }
01193 #ifndef DONT_USE_WRAPUNWRAP
01194   return (Xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
01195                            gd->ctx, gd->sec.qop, gd->sec.svc, gd->seq));
01196 #else
01197   return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr,
01198                            gd->ctx, gd->sec.qop, gd->sec.svc, gd->seq));
01199 #endif
01200 }
01201 
01202 int copy_svc_authgss(SVCXPRT *xprt_copy, SVCXPRT *xprt_orig)
01203 {
01204   if(xprt_orig->xp_auth)
01205     {
01206       if(xprt_orig->xp_auth->svc_ah_ops == &Svc_auth_gss_ops ||
01207          xprt_orig->xp_auth->svc_ah_ops == &Svc_auth_gss_copy_ops)
01208         {
01209           /* Copy GSS auth */
01210           struct svc_rpc_gss_data *gd_o, *gd_c;
01211 
01212           gd_o = SVCAUTH_PRIVATE(xprt_orig->xp_auth);
01213           xprt_copy->xp_auth = gsh_malloc(sizeof(SVCAUTH));
01214           if(xprt_copy->xp_auth == NULL)
01215             return 0;
01216           gd_c = gsh_malloc(sizeof(*gd_c));
01217           if(gd_c == NULL)
01218             {
01219               gsh_free(xprt_copy->xp_auth);
01220               xprt_copy->xp_auth = NULL;
01221               return 0;
01222             }
01223 
01224           /* Copy everything over */
01225           memcpy(gd_c, gd_o, sizeof(*gd_c));
01226 
01227           /* Leave the original without the various pointed to things */
01228           gd_o->checksum.length = 0;
01229           gd_o->checksum.value  = NULL;
01230           gd_o->cname.length    = 0;
01231           gd_o->cname.value     = NULL;
01232           gd_o->client_name     = NULL;
01233           gd_o->ctx             = NULL;
01234 
01235           /* fill in xp_auth */
01236           xprt_copy->xp_auth->svc_ah_private = (void *)gd_c;
01237           xprt_copy->xp_auth->svc_ah_ops = &Svc_auth_gss_ops;
01238         }
01239       else
01240         {
01241           /* Should be Svc_auth_none */
01242           if(xprt_orig->xp_auth != &Svc_auth_none)
01243             LogFullDebug(COMPONENT_RPCSEC_GSS,
01244                          "copy_svc_authgss copying unknown xp_auth");
01245           xprt_copy->xp_auth = xprt_orig->xp_auth;
01246         }
01247     }
01248   else
01249     xprt_copy->xp_auth = NULL;
01250   return 1;
01251 }
01252