nfs-ganesha 1.4

nfs4_op_setclientid.c

Go to the documentation of this file.
00001 /*
00002  * vim:expandtab:shiftwidth=8:tabstop=8:
00003  *
00004  * Copyright CEA/DAM/DIF  (2008)
00005  * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
00006  *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
00007  *
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public License
00011  * as published by the Free Software Foundation; either version 3 of
00012  * the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00022  * 02110-1301 USA
00023  *
00024  * ---------------------------------------
00025  */
00026 
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 <pthread.h>
00044 #include "log.h"
00045 #include "nfs4.h"
00046 #include "sal_functions.h"
00047 #include "nfs_proto_functions.h"
00048 #include "nfs_core.h"
00049 
00066 int nfs4_op_setclientid(struct nfs_argop4 * op,
00067                         compound_data_t   * data,
00068                         struct nfs_resop4 * resp)
00069 {
00070   char                  str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
00071   char                  str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
00072   char                  str_client_addr[SOCK_NAME_MAX];
00073   nfs_client_record_t * pclient_record;
00074   nfs_client_id_t     * pconf;
00075   nfs_client_id_t     * punconf;
00076   clientid4             clientid;
00077   verifier4             verifier;
00078   sockaddr_t            client_addr;
00079   int                   rc;
00080 
00081 #define arg_SETCLIENTID4       op->nfs_argop4_u.opsetclientid
00082 #define res_SETCLIENTID4       resp->nfs_resop4_u.opsetclientid
00083 #define res_SETCLIENTID4_INUSE resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using
00084 
00085   resp->resop = NFS4_OP_SETCLIENTID;
00086 
00087   copy_xprt_addr(&client_addr, data->reqp->rq_xprt);
00088 
00089   if(isDebug(COMPONENT_CLIENTID))
00090     {
00091       sprint_sockip(&client_addr, str_client_addr, sizeof(str_client_addr));
00092 
00093       DisplayOpaqueValue(arg_SETCLIENTID4.client.id.id_val,
00094                          arg_SETCLIENTID4.client.id.id_len,
00095                          str_client);
00096 
00097       sprint_mem(str_verifier,
00098                  arg_SETCLIENTID4.client.verifier,
00099                  NFS4_VERIFIER_SIZE);
00100     }
00101 
00102   LogDebug(COMPONENT_CLIENTID,
00103            "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u",
00104            str_client_addr, str_client, str_verifier,
00105            arg_SETCLIENTID4.callback.cb_program,
00106            arg_SETCLIENTID4.callback.cb_location.r_addr,
00107            arg_SETCLIENTID4.callback.cb_location.r_netid,
00108            arg_SETCLIENTID4.callback_ident);
00109 
00110   /* Do we already have one or more records for client id (x)? */
00111   pclient_record = get_client_record(arg_SETCLIENTID4.client.id.id_val,
00112                                      arg_SETCLIENTID4.client.id.id_len);
00113   if(pclient_record == NULL)
00114     {
00115       /* Some major failure */
00116       LogCrit(COMPONENT_CLIENTID,
00117               "SETCLIENTID failed");
00118 
00119       res_SETCLIENTID4.status = NFS4ERR_SERVERFAULT;
00120 
00121       return res_SETCLIENTID4.status;
00122     }
00123 
00124   /*
00125    * The following checks are based on RFC3530bis draft 16
00126    *
00127    * This attempts to implement the logic described in 15.35.5. IMPLEMENTATION
00128    * Consider the major bullets as CASE 1, CASE 2, CASE 3, CASE 4, and CASE 5.
00129    */
00130 
00131   P(pclient_record->cr_mutex);
00132 
00133   if(isFullDebug(COMPONENT_CLIENTID))
00134     {
00135       char str[HASHTABLE_DISPLAY_STRLEN];
00136 
00137       display_client_record(pclient_record, str);
00138 
00139       LogFullDebug(COMPONENT_CLIENTID,
00140                    "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p",
00141                    str,
00142                    pclient_record->cr_pconfirmed_id,
00143                    pclient_record->cr_punconfirmed_id);
00144     }
00145 
00146   pconf = pclient_record->cr_pconfirmed_id;
00147 
00148   if(pconf != NULL)
00149     {
00150       /* Need a reference to the confirmed record for below */
00151       inc_client_id_ref(pconf);
00152 
00153       if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
00154          !cmp_sockaddr(&pconf->cid_client_addr, &client_addr, IGNORE_PORT))
00155         {
00156           /* CASE 1:
00157            *
00158            * Confirmed record exists and not the same principal
00159            */
00160           if(isDebug(COMPONENT_CLIENTID))
00161             {
00162               char confirmed_addr[SOCK_NAME_MAX];
00163 
00164               sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));
00165 
00166               LogDebug(COMPONENT_CLIENTID,
00167                        "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
00168                        pconf->cid_clientid, str_client, confirmed_addr);
00169             }
00170 
00171           res_SETCLIENTID4.status = NFS4ERR_CLID_INUSE;
00172           res_SETCLIENTID4_INUSE.r_netid
00173                = (char *) netid_nc_table[pconf->cid_cb.cid_addr.nc].netid;
00174           res_SETCLIENTID4_INUSE.r_addr
00175                = gsh_strdup(pconf->cid_cb.cid_client_r_addr);
00176 
00177           /* Release our reference to the confirmed clientid. */
00178           dec_client_id_ref(pconf);
00179 
00180           goto out;
00181         }
00182 
00183       /* Check if confirmed record is for (v, x, c, l, s) */
00184       if(memcmp(arg_SETCLIENTID4.client.verifier,
00185                 pconf->cid_incoming_verifier,
00186                 NFS4_VERIFIER_SIZE) == 0)
00187         {
00188           /* CASE 2:
00189            *
00190            * A confirmed record exists for this long form client id and
00191            * verifier.
00192            *
00193            * Consider this to be a possible update of the call-back information.
00194            *
00195            * Remove any pre-existing unconfirmed record for (v, x, c).
00196            *
00197            * Return the same short form client id (c), but a new
00198            * setclientid_confirm verifier (t).
00199            */
00200            LogFullDebug(COMPONENT_CLIENTID,
00201                         "Update ClientId %"PRIx64"->%s",
00202                         pconf->cid_clientid, str_client);
00203 
00204            clientid = pconf->cid_clientid;
00205 
00206            new_clientifd_verifier(verifier);
00207         }
00208       else
00209         {
00210           /* Must be CASE 3 or CASE 4
00211            *
00212            * Confirmed record is for (u, x, c, l, s).
00213            *
00214            * These are actually the same, doesn't really matter if an
00215            * unconfirmed record exists or not. Any existing unconfirmed record
00216            * will be removed and a new unconfirmed record added.
00217            *
00218            * Return a new short form clientid (d) and a new setclientid_confirm
00219            * verifier (t). (Note the spec calls the values e and r for CASE 4).
00220            */
00221           LogFullDebug(COMPONENT_CLIENTID,
00222                        "Replace ClientId %"PRIx64"->%s",
00223                        pconf->cid_clientid, str_client);
00224 
00225           clientid = new_clientid();
00226 
00227           new_clientifd_verifier(verifier);
00228         }
00229 
00230       /* Release our reference to the confirmed clientid. */
00231       dec_client_id_ref(pconf);
00232     }
00233   else
00234     {
00235       /* CASE 5:
00236        *
00237        *
00238        * Remove any existing unconfirmed record.
00239        *
00240        * Return a new short form clientid (d) and a new setclientid_confirm
00241        * verifier (t).
00242        */
00243       LogFullDebug(COMPONENT_CLIENTID,
00244                    "New client");
00245 
00246       clientid = new_clientid();
00247 
00248       new_clientifd_verifier(verifier);
00249     }
00250 
00251   /* At this point, no matter what the case was above, we should remove any
00252    * pre-existing unconfirmed record.
00253    */
00254 
00255   punconf = pclient_record->cr_punconfirmed_id;
00256 
00257   if(punconf != NULL)
00258     {
00259       /* Delete the unconfirmed clientid record. Because we have the cr_mutex,
00260        * we have won any race to deal with this clientid record (whether we
00261        * raced with a SETCLIENTID_CONFIRM or the reaper thread (if either of
00262        * those operations had won the race, cr_punconfirmed_id would have been
00263        * NULL).
00264        */
00265       if(isDebug(COMPONENT_CLIENTID))
00266         {
00267           char str[HASHTABLE_DISPLAY_STRLEN];
00268 
00269           display_client_id_rec(punconf, str);
00270 
00271           LogDebug(COMPONENT_CLIENTID,
00272                    "Replacing %s",
00273                    str);
00274         }
00275 
00276       /* unhash the clientid record */
00277       remove_unconfirmed_client_id(punconf);
00278 
00279       punconf = NULL;
00280     }
00281 
00282   /* Now we can proceed to build the new unconfirmed record. We have determined
00283    * the clientid and setclientid_confirm values above.
00284    */
00285 
00286   punconf = create_client_id(clientid,
00287                              pclient_record,
00288                              &client_addr,
00289                              &data->credential);
00290 
00291   if(punconf == NULL)
00292     {
00293       /* Error already logged, return */
00294       res_SETCLIENTID4.status = NFS4ERR_RESOURCE;
00295 
00296       goto out;
00297     }
00298 
00299   strncpy(punconf->cid_cb.cid_client_r_addr,
00300           arg_SETCLIENTID4.callback.cb_location.r_addr,
00301           SOCK_NAME_MAX);
00302 
00303   nfs_set_client_location(punconf,
00304                           &arg_SETCLIENTID4.callback.cb_location);
00305   
00306   memcpy(punconf->cid_incoming_verifier,
00307          arg_SETCLIENTID4.client.verifier,
00308          NFS4_VERIFIER_SIZE);
00309   memcpy(punconf->cid_verifier, verifier, sizeof(NFS4_write_verifier));
00310 
00311   punconf->cid_cb.cid_program = arg_SETCLIENTID4.callback.cb_program;
00312   punconf->cid_cb.cb_u.v40.cb_callback_ident = arg_SETCLIENTID4.callback_ident;
00313 
00314   rc = nfs_client_id_insert(punconf);
00315 
00316   if(rc != CLIENT_ID_SUCCESS)
00317     {
00318       /* Record is already freed, return. */
00319       if(rc == CLIENT_ID_INSERT_MALLOC_ERROR)
00320         res_SETCLIENTID4.status = NFS4ERR_RESOURCE;
00321       else
00322         res_SETCLIENTID4.status = NFS4ERR_SERVERFAULT;
00323 
00324       goto out;
00325     }
00326 
00327   if(isDebug(COMPONENT_CLIENTID))
00328     {
00329       char str[HASHTABLE_DISPLAY_STRLEN];
00330 
00331       sprint_mem(str_verifier,
00332                  verifier,
00333                  NFS4_VERIFIER_SIZE);
00334 
00335       display_client_id_rec(punconf, str);
00336 
00337       LogDebug(COMPONENT_CLIENTID,
00338                "SETCLIENTID reply Verifier=%s %s",
00339                str_verifier, str);
00340     }
00341 
00342   res_SETCLIENTID4.status = NFS4_OK;
00343 
00344   res_SETCLIENTID4.SETCLIENTID4res_u.resok4.clientid = clientid;
00345 
00346   memcpy(res_SETCLIENTID4.SETCLIENTID4res_u.resok4.setclientid_confirm,
00347          &verifier,
00348          NFS4_VERIFIER_SIZE);
00349 
00350  out:
00351 
00352   V(pclient_record->cr_mutex);
00353 
00354   /* Release our reference to the client record */
00355   dec_client_record_ref(pclient_record);
00356 
00357   return res_SETCLIENTID4.status;
00358 }                               /* nfs4_op_setclientid */
00359 
00370 void nfs4_op_setclientid_Free(SETCLIENTID4res * resp)
00371 {
00372   if(resp->status == NFS4ERR_CLID_INUSE)
00373     {
00374       if(resp->SETCLIENTID4res_u.client_using.r_addr != NULL)
00375         gsh_free(resp->SETCLIENTID4res_u.client_using.r_addr);
00376     }
00377   return;
00378 }                               /* nfs4_op_setclientid_Free */