Merge branch 'nfs-for-next' of git://linux-nfs.org/~trondmy/nfs-2.6 into for-3.10
J. Bruce Fields [Mon, 29 Apr 2013 18:03:30 +0000 (14:03 -0400)]
Note conflict: Chuck's patches modified (and made static)
gss_mech_get_by_OID, which is still needed by gss-proxy patches.

The conflict resolution is a bit minimal; we may want some more cleanup.

1  2 
fs/nfs/super.c
fs/nfsd/nfs4xdr.c
include/linux/sunrpc/gss_api.h
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_mech.c
net/sunrpc/auth_gss/gss_mech_switch.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_upcall.h
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c

diff --cc fs/nfs/super.c
Simple merge
Simple merge
@@@ -119,9 -130,11 +132,15 @@@ struct gss_api_ops 
  int gss_mech_register(struct gss_api_mech *);
  void gss_mech_unregister(struct gss_api_mech *);
  
 +/* returns a mechanism descriptor given an OID, and increments the mechanism's
 + * reference count. */
- struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
++struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *);
++
+ /* Given a GSS security tuple, look up a pseudoflavor */
+ rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
+ /* Given a pseudoflavor, look up a GSS security tuple */
+ int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *);
  
  /* Returns a reference to a mechanism, given a name like "krb5" etc. */
  struct gss_api_mech *gss_mech_get_by_name(const char *);
Simple merge
Simple merge
@@@ -169,12 -174,16 +174,16 @@@ struct gss_api_mech * gss_mech_get_by_n
        }
        return gm;
  }
- EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
  
- struct gss_api_mech *
- gss_mech_get_by_OID(struct xdr_netobj *obj)
 -static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
++struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
  {
        struct gss_api_mech     *pos, *gm = NULL;
+       char buf[32];
+       if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0)
+               return NULL;
+       dprintk("RPC:       %s(%s)\n", __func__, buf);
+       request_module("rpc-auth-gss-%s", buf);
  
        spin_lock(&registered_mechs_lock);
        list_for_each_entry(pos, &registered_mechs, gm_list) {
index 3f874d7,0000000..c632736
mode 100644,000000..100644
--- /dev/null
@@@ -1,357 -1,0 +1,358 @@@
 +/*
 + *  linux/net/sunrpc/gss_rpc_upcall.c
 + *
 + *  Copyright (C) 2012 Simo Sorce <simo@redhat.com>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#include <linux/types.h>
 +#include <linux/un.h>
 +
 +#include <linux/sunrpc/svcauth.h>
 +#include "gss_rpc_upcall.h"
 +
 +#define GSSPROXY_SOCK_PATHNAME        "/var/run/gssproxy.sock"
 +
 +#define GSSPROXY_PROGRAM      (400112u)
 +#define GSSPROXY_VERS_1               (1u)
 +
 +/*
 + * Encoding/Decoding functions
 + */
 +
 +enum {
 +      GSSX_NULL = 0,  /* Unused */
 +        GSSX_INDICATE_MECHS = 1,
 +        GSSX_GET_CALL_CONTEXT = 2,
 +        GSSX_IMPORT_AND_CANON_NAME = 3,
 +        GSSX_EXPORT_CRED = 4,
 +        GSSX_IMPORT_CRED = 5,
 +        GSSX_ACQUIRE_CRED = 6,
 +        GSSX_STORE_CRED = 7,
 +        GSSX_INIT_SEC_CONTEXT = 8,
 +        GSSX_ACCEPT_SEC_CONTEXT = 9,
 +        GSSX_RELEASE_HANDLE = 10,
 +        GSSX_GET_MIC = 11,
 +        GSSX_VERIFY = 12,
 +        GSSX_WRAP = 13,
 +        GSSX_UNWRAP = 14,
 +        GSSX_WRAP_SIZE_LIMIT = 15,
 +};
 +
 +#define PROC(proc, name)                              \
 +[GSSX_##proc] = {                                     \
 +      .p_proc   = GSSX_##proc,                        \
 +      .p_encode = (kxdreproc_t)gssx_enc_##name,       \
 +      .p_decode = (kxdrdproc_t)gssx_dec_##name,       \
 +      .p_arglen = GSSX_ARG_##name##_sz,               \
 +      .p_replen = GSSX_RES_##name##_sz,               \
 +      .p_statidx = GSSX_##proc,                       \
 +      .p_name   = #proc,                              \
 +}
 +
 +struct rpc_procinfo gssp_procedures[] = {
 +      PROC(INDICATE_MECHS, indicate_mechs),
 +        PROC(GET_CALL_CONTEXT, get_call_context),
 +        PROC(IMPORT_AND_CANON_NAME, import_and_canon_name),
 +        PROC(EXPORT_CRED, export_cred),
 +        PROC(IMPORT_CRED, import_cred),
 +        PROC(ACQUIRE_CRED, acquire_cred),
 +        PROC(STORE_CRED, store_cred),
 +        PROC(INIT_SEC_CONTEXT, init_sec_context),
 +        PROC(ACCEPT_SEC_CONTEXT, accept_sec_context),
 +        PROC(RELEASE_HANDLE, release_handle),
 +        PROC(GET_MIC, get_mic),
 +        PROC(VERIFY, verify),
 +        PROC(WRAP, wrap),
 +        PROC(UNWRAP, unwrap),
 +        PROC(WRAP_SIZE_LIMIT, wrap_size_limit),
 +};
 +
 +
 +
 +/*
 + * Common transport functions
 + */
 +
 +static const struct rpc_program gssp_program;
 +
 +static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt)
 +{
 +      static const struct sockaddr_un gssp_localaddr = {
 +              .sun_family             = AF_LOCAL,
 +              .sun_path               = GSSPROXY_SOCK_PATHNAME,
 +      };
 +      struct rpc_create_args args = {
 +              .net            = net,
 +              .protocol       = XPRT_TRANSPORT_LOCAL,
 +              .address        = (struct sockaddr *)&gssp_localaddr,
 +              .addrsize       = sizeof(gssp_localaddr),
 +              .servername     = "localhost",
 +              .program        = &gssp_program,
 +              .version        = GSSPROXY_VERS_1,
 +              .authflavor     = RPC_AUTH_NULL,
 +              /*
 +               * Note we want connection to be done in the caller's
 +               * filesystem namespace.  We therefore turn off the idle
 +               * timeout, which would result in reconnections being
 +               * done without the correct namespace:
 +               */
 +              .flags          = RPC_CLNT_CREATE_NOPING |
 +                                RPC_CLNT_CREATE_NO_IDLE_TIMEOUT
 +      };
 +      struct rpc_clnt *clnt;
 +      int result = 0;
 +
 +      clnt = rpc_create(&args);
 +      if (IS_ERR(clnt)) {
 +              dprintk("RPC:       failed to create AF_LOCAL gssproxy "
 +                              "client (errno %ld).\n", PTR_ERR(clnt));
 +              result = -PTR_ERR(clnt);
 +              *_clnt = NULL;
 +              goto out;
 +      }
 +
 +      dprintk("RPC:       created new gssp local client (gssp_local_clnt: "
 +                      "%p)\n", clnt);
 +      *_clnt = clnt;
 +
 +out:
 +      return result;
 +}
 +
 +void init_gssp_clnt(struct sunrpc_net *sn)
 +{
 +      mutex_init(&sn->gssp_lock);
 +      sn->gssp_clnt = NULL;
 +      init_waitqueue_head(&sn->gssp_wq);
 +}
 +
 +int set_gssp_clnt(struct net *net)
 +{
 +      struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 +      struct rpc_clnt *clnt;
 +      int ret;
 +
 +      mutex_lock(&sn->gssp_lock);
 +      ret = gssp_rpc_create(net, &clnt);
 +      if (!ret) {
 +              if (sn->gssp_clnt)
 +                      rpc_shutdown_client(sn->gssp_clnt);
 +              sn->gssp_clnt = clnt;
 +      }
 +      mutex_unlock(&sn->gssp_lock);
 +      wake_up(&sn->gssp_wq);
 +      return ret;
 +}
 +
 +void clear_gssp_clnt(struct sunrpc_net *sn)
 +{
 +      mutex_lock(&sn->gssp_lock);
 +      if (sn->gssp_clnt) {
 +              rpc_shutdown_client(sn->gssp_clnt);
 +              sn->gssp_clnt = NULL;
 +      }
 +      mutex_unlock(&sn->gssp_lock);
 +}
 +
 +static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
 +{
 +      struct rpc_clnt *clnt;
 +
 +      mutex_lock(&sn->gssp_lock);
 +      clnt = sn->gssp_clnt;
 +      if (clnt)
 +              atomic_inc(&clnt->cl_count);
 +      mutex_unlock(&sn->gssp_lock);
 +      return clnt;
 +}
 +
 +static int gssp_call(struct net *net, struct rpc_message *msg)
 +{
 +      struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 +      struct rpc_clnt *clnt;
 +      int status;
 +
 +      clnt = get_gssp_clnt(sn);
 +      if (!clnt)
 +              return -EIO;
 +      status = rpc_call_sync(clnt, msg, 0);
 +      if (status < 0) {
 +              dprintk("gssp: rpc_call returned error %d\n", -status);
 +              switch (status) {
 +              case -EPROTONOSUPPORT:
 +                      status = -EINVAL;
 +                      break;
 +              case -ECONNREFUSED:
 +              case -ETIMEDOUT:
 +              case -ENOTCONN:
 +                      status = -EAGAIN;
 +                      break;
 +              case -ERESTARTSYS:
 +                      if (signalled ())
 +                              status = -EINTR;
 +                      break;
 +              default:
 +                      break;
 +              }
 +      }
 +      rpc_release_client(clnt);
 +      return status;
 +}
 +
 +
 +/*
 + * Public functions
 + */
 +
 +/* numbers somewhat arbitrary but large enough for current needs */
 +#define GSSX_MAX_OUT_HANDLE   128
- #define GSSX_MAX_MECH_OID     16
 +#define GSSX_MAX_SRC_PRINC    256
 +#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
 +                      GSSX_max_oid_sz + \
 +                      GSSX_max_princ_sz + \
 +                      sizeof(struct svc_cred))
 +
 +int gssp_accept_sec_context_upcall(struct net *net,
 +                              struct gssp_upcall_data *data)
 +{
 +      struct gssx_ctx ctxh = {
 +              .state = data->in_handle
 +      };
 +      struct gssx_arg_accept_sec_context arg = {
 +              .input_token = data->in_token,
 +      };
 +      struct gssx_ctx rctxh = {
 +              /*
 +               * pass in the max length we expect for each of these
 +               * buffers but let the xdr code kmalloc them:
 +               */
 +              .exported_context_token.len = GSSX_max_output_handle_sz,
-               .mech.len = GSSX_max_oid_sz,
++              .mech.len = GSS_OID_MAX_LEN,
 +              .src_name.display_name.len = GSSX_max_princ_sz
 +      };
 +      struct gssx_res_accept_sec_context res = {
 +              .context_handle = &rctxh,
 +              .output_token = &data->out_token
 +      };
 +      struct rpc_message msg = {
 +              .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT],
 +              .rpc_argp = &arg,
 +              .rpc_resp = &res,
 +              .rpc_cred = NULL, /* FIXME ? */
 +      };
 +      struct xdr_netobj client_name = { 0 , NULL };
 +      int ret;
 +
 +      if (data->in_handle.len != 0)
 +              arg.context_handle = &ctxh;
 +      res.output_token->len = GSSX_max_output_token_sz;
 +
 +      /* use nfs/ for targ_name ? */
 +
 +      ret = gssp_call(net, &msg);
 +
 +      /* we need to fetch all data even in case of error so
 +       * that we can free special strctures is they have been allocated */
 +      data->major_status = res.status.major_status;
 +      data->minor_status = res.status.minor_status;
 +      if (res.context_handle) {
 +              data->out_handle = rctxh.exported_context_token;
-               data->mech_oid = rctxh.mech;
++              data->mech_oid.len = rctxh.mech.len;
++              memcpy(data->mech_oid.data, rctxh.mech.data,
++                                              data->mech_oid.len);
 +              client_name = rctxh.src_name.display_name;
 +      }
 +
 +      if (res.options.count == 1) {
 +              gssx_buffer *value = &res.options.data[0].value;
 +              /* Currently we only decode CREDS_VALUE, if we add
 +               * anything else we'll have to loop and match on the
 +               * option name */
 +              if (value->len == 1) {
 +                      /* steal group info from struct svc_cred */
 +                      data->creds = *(struct svc_cred *)value->data;
 +                      data->found_creds = 1;
 +              }
 +              /* whether we use it or not, free data */
 +              kfree(value->data);
 +      }
 +
 +      if (res.options.count != 0) {
 +              kfree(res.options.data);
 +      }
 +
 +      /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
 +      if (data->found_creds && client_name.data != NULL) {
 +              char *c;
 +
 +              data->creds.cr_principal = kstrndup(client_name.data,
 +                                              client_name.len, GFP_KERNEL);
 +              if (data->creds.cr_principal) {
 +                      /* terminate and remove realm part */
 +                      c = strchr(data->creds.cr_principal, '@');
 +                      if (c) {
 +                              *c = '\0';
 +
 +                              /* change service-hostname delimiter */
 +                              c = strchr(data->creds.cr_principal, '/');
 +                              if (c) *c = '@';
 +                      }
 +                      if (!c) {
 +                              /* not a service principal */
 +                              kfree(data->creds.cr_principal);
 +                              data->creds.cr_principal = NULL;
 +                      }
 +              }
 +      }
 +      kfree(client_name.data);
 +
 +      return ret;
 +}
 +
 +void gssp_free_upcall_data(struct gssp_upcall_data *data)
 +{
 +      kfree(data->in_handle.data);
 +      kfree(data->out_handle.data);
 +      kfree(data->out_token.data);
 +      kfree(data->mech_oid.data);
 +      free_svc_cred(&data->creds);
 +}
 +
 +/*
 + * Initialization stuff
 + */
 +
 +static const struct rpc_version gssp_version1 = {
 +      .number         = GSSPROXY_VERS_1,
 +      .nrprocs        = ARRAY_SIZE(gssp_procedures),
 +      .procs          = gssp_procedures,
 +};
 +
 +static const struct rpc_version *gssp_version[] = {
 +      NULL,
 +      &gssp_version1,
 +};
 +
 +static struct rpc_stat gssp_stats;
 +
 +static const struct rpc_program gssp_program = {
 +      .name           = "gssproxy",
 +      .number         = GSSPROXY_PROGRAM,
 +      .nrvers         = ARRAY_SIZE(gssp_version),
 +      .version        = gssp_version,
 +      .stats          = &gssp_stats,
 +};
index 4c2caaa,0000000..1e542ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,47 -1,0 +1,48 @@@
 +/*
 + *  linux/net/sunrpc/gss_rpc_upcall.h
 + *
 + *  Copyright (C) 2012 Simo Sorce <simo@redhat.com>
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
 + * the Free Software Foundation; either version 2 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#ifndef _GSS_RPC_UPCALL_H
 +#define _GSS_RPC_UPCALL_H
 +
++#include <linux/sunrpc/gss_api.h>
 +#include <linux/sunrpc/auth_gss.h>
 +#include "gss_rpc_xdr.h"
 +#include "../netns.h"
 +
 +struct gssp_upcall_data {
 +      struct xdr_netobj in_handle;
 +      struct gssp_in_token in_token;
 +      struct xdr_netobj out_handle;
 +      struct xdr_netobj out_token;
-       struct xdr_netobj mech_oid;
++      struct rpcsec_gss_oid mech_oid;
 +      struct svc_cred creds;
 +      int found_creds;
 +      int major_status;
 +      int minor_status;
 +};
 +
 +int gssp_accept_sec_context_upcall(struct net *net,
 +                              struct gssp_upcall_data *data);
 +void gssp_free_upcall_data(struct gssp_upcall_data *data);
 +
 +void init_gssp_clnt(struct sunrpc_net *);
 +int set_gssp_clnt(struct net *);
 +void clear_gssp_clnt(struct sunrpc_net *);
 +#endif /* _GSS_RPC_UPCALL_H */
Simple merge
Simple merge