nfs-ganesha 1.4

nfs41_op_exchange_id.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 "mount.h"
00047 #include "nfs_core.h"
00048 #include "nfs_proto_functions.h"
00049 #include "sal_functions.h"
00050 
00067 #if 0
00068 static uint32_t all_eia_flags =
00069     EXCHGID4_FLAG_SUPP_MOVED_MIGR |
00070     EXCHGID4_FLAG_BIND_PRINC_STATEID |
00071     EXCHGID4_FLAG_USE_NON_PNFS |
00072     EXCHGID4_FLAG_USE_PNFS_MDS |
00073     EXCHGID4_FLAG_USE_PNFS_DS |
00074     EXCHGID4_FLAG_MASK_PNFS |
00075     EXCHGID4_FLAG_UPD_CONFIRMED_REC_A | EXCHGID4_FLAG_CONFIRMED_R;
00076 #endif
00077 
00078 int nfs41_op_exchange_id(struct nfs_argop4 *op,
00079                          compound_data_t * data, struct nfs_resop4 *resp)
00080 {
00081   char                  str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
00082   char                  str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
00083   char                  str_client_addr[SOCK_NAME_MAX];
00084   nfs_client_record_t * pclient_record;
00085   nfs_client_id_t     * pconf;
00086   nfs_client_id_t     * punconf;
00087   sockaddr_t            client_addr;
00088   int                   rc;
00089   int                   len;
00090   char                * temp;
00091   bool_t                update;
00092   const char          * update_str;
00093   log_components_t      component = COMPONENT_CLIENTID;
00094 
00095 #if 0 
00096   /* Check flags value (test EID4) */
00097   if(arg_EXCHANGE_ID4.eia_flags & all_eia_flags != arg_EXCHANGE_ID4.eia_flags)
00098     {
00099       res_EXCHANGE_ID4.eir_status = NFS4ERR_INVAL;
00100       return res_EXCHANGE_ID4.eir_status;
00101     }
00102 #endif
00103 
00104   if(isDebug(COMPONENT_SESSIONS))
00105     component = COMPONENT_SESSIONS;
00106 
00107 #define arg_EXCHANGE_ID4    op->nfs_argop4_u.opexchange_id
00108 #define res_EXCHANGE_ID4    resp->nfs_resop4_u.opexchange_id
00109 #define res_EXCHANGE_ID4_ok resp->nfs_resop4_u.opexchange_id.EXCHANGE_ID4res_u.eir_resok4
00110 
00111   resp->resop = NFS4_OP_EXCHANGE_ID;
00112 
00113   copy_xprt_addr(&client_addr, data->reqp->rq_xprt);
00114 
00115   update = (arg_EXCHANGE_ID4.eia_flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) != 0;
00116 
00117   if(isDebug(component))
00118     {
00119       sprint_sockip(&client_addr, str_client_addr, sizeof(str_client_addr));
00120 
00121       DisplayOpaqueValue(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
00122                          arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len,
00123                          str_client);
00124 
00125       sprint_mem(str_verifier,
00126                  arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
00127                  NFS4_VERIFIER_SIZE);
00128 
00129       update_str = update ? "UPDATE" : "NO UPDATE";
00130     }
00131 
00132   LogDebug(component,
00133            "EXCHANGE_ID Client addr=%s id=%s verf=%s %s --------------------",
00134            str_client_addr, str_client, str_verifier, update_str);
00135 
00136   /* Do we already have one or more records for client id (x)? */
00137   pclient_record = get_client_record(arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_val,
00138                                      arg_EXCHANGE_ID4.eia_clientowner.co_ownerid.co_ownerid_len);
00139   if(pclient_record == NULL)
00140     {
00141       /* Some major failure */
00142       LogCrit(component,
00143               "EXCHANGE_ID failed");
00144       res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
00145       return res_EXCHANGE_ID4.eir_status;
00146     }
00147 
00148   /*
00149    * The following checks are based on RFC5661
00150    *
00151    * This attempts to implement the logic described in 18.35.4. IMPLEMENTATION
00152    */
00153 
00154   P(pclient_record->cr_mutex);
00155 
00156   if(isFullDebug(COMPONENT_CLIENTID))
00157     {
00158       char str[HASHTABLE_DISPLAY_STRLEN];
00159 
00160       display_client_record(pclient_record, str);
00161 
00162       LogFullDebug(COMPONENT_CLIENTID,
00163                    "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p",
00164                    str,
00165                    pclient_record->cr_pconfirmed_id,
00166                    pclient_record->cr_punconfirmed_id);
00167     }
00168 
00169   pconf = pclient_record->cr_pconfirmed_id;
00170 
00171   if(pconf != NULL)
00172     {
00173       /* Need a reference to the confirmed record for below */
00174       inc_client_id_ref(pconf);
00175     }
00176 
00177   if(pconf != NULL && !update)
00178     {
00179       /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A not set */
00181       if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
00182          !cmp_sockaddr(&pconf->cid_client_addr, &client_addr, IGNORE_PORT))
00183         {
00185           P(pconf->cid_mutex);
00186 
00187           if(valid_lease(pconf))
00188             {
00189               V(pconf->cid_mutex);
00190 
00191               /* CASE 3, client collisions, old clientid is expired */
00192               if(isDebug(COMPONENT_CLIENTID))
00193                 {
00194                   char str[HASHTABLE_DISPLAY_STRLEN];
00195 
00196                   display_client_id_rec(pconf, str);
00197                   LogDebug(COMPONENT_CLIENTID,
00198                            "Expiring %s",
00199                            str);
00200                 }
00201               /* Expire clientid and release our reference. */
00202               nfs_client_id_expire(pconf);
00203 
00204               dec_client_id_ref(pconf);
00205 
00206               pconf = NULL;
00207             }
00208           else
00209             {
00210               V(pconf->cid_mutex);
00211 
00212               /* CASE 3, client collisions, old clientid is not expired */
00213               if(isDebug(component))
00214                 {
00215                   char confirmed_addr[SOCK_NAME_MAX];
00216 
00217                   sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));
00218 
00219                   LogDebug(component,
00220                            "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
00221                            pconf->cid_clientid, str_client, confirmed_addr);
00222                 }
00223 
00224               res_EXCHANGE_ID4.eir_status = NFS4ERR_CLID_INUSE;
00225 
00226               /* Release our reference to the confirmed clientid. */
00227               dec_client_id_ref(pconf);
00228 
00229               goto out;
00230             }
00231         }
00232       else if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
00233                      pconf->cid_incoming_verifier,
00234                      NFS4_VERIFIER_SIZE) == 0)
00235         {
00236           /* CASE 2, Non-Update on Existing Client ID */
00237           /* Return what was last returned without changing any refcounts */
00238           LogDebug(COMPONENT_CLIENTID,
00239                    "Non-update of confirmed ClientId %"PRIx64"->%s",
00240                    pconf->cid_clientid, str_client);
00241 
00242           punconf = pconf;
00243 
00244           goto return_ok;
00245         }
00246       else
00247         {
00248           /* CASE 5, client restart */
00250           LogDebug(component,
00251                    "Restarted ClientId %"PRIx64"->%s",
00252                    pconf->cid_clientid, str_client);
00253           
00254         }
00255     }
00256   else if(pconf != NULL)
00257     {
00258       /* EXCHGID4_FLAG_UPD_CONFIRMED_REC_A set */
00259       if(memcmp(arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
00260                 pconf->cid_incoming_verifier,
00261                 NFS4_VERIFIER_SIZE) == 0)
00262         {
00264           if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
00265              !cmp_sockaddr(&pconf->cid_client_addr, &client_addr, IGNORE_PORT))
00266             {
00267               /* CASE 9, Update but wrong principal */
00268               if(isDebug(component))
00269                 {
00270                   char confirmed_addr[SOCK_NAME_MAX];
00271 
00272                   sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));
00273 
00274                   LogDebug(component,
00275                            "Confirmed ClientId %"PRIx64"->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_PERM",
00276                            pconf->cid_clientid, str_client, confirmed_addr);
00277                 }
00278 
00279               res_EXCHANGE_ID4.eir_status = NFS4ERR_PERM;
00280             }
00281           else
00282             {
00283               /* CASE 6, Update */
00285               LogMajor(component,
00286                        "EXCHANGE_ID Update not supported");
00287               res_EXCHANGE_ID4.eir_status = NFS4ERR_NOTSUPP;
00288             }
00289         }
00290       else
00291         {
00292           /* CASE 8, Update but wrong verifier */
00293           if(isDebug(component))
00294             {
00295               char str_old_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
00296 
00297               sprint_mem(str_old_verifier,
00298                          pconf->cid_incoming_verifier,
00299                          NFS4_VERIFIER_SIZE);
00300 
00301               LogDebug(component,
00302                        "Confirmed clientid %"PRIx64"->'%s': Verifiers do not match... confirmed verifier=%s",
00303                        pconf->cid_clientid, str_client, str_old_verifier);
00304             }
00305 
00306           res_EXCHANGE_ID4.eir_status = NFS4ERR_NOT_SAME;
00307         }
00308 
00309       /* Release our reference to the confirmed clientid. */
00310       dec_client_id_ref(pconf);
00311 
00312       goto out;
00313     }
00314   else if(pconf == NULL && update)
00315     {
00316       LogDebug(component,
00317                "No confirmed clientid to update for %s",
00318                str_client);
00319 
00320       res_EXCHANGE_ID4.eir_status = NFS4ERR_NOENT;
00321 
00322       goto out;
00323     }
00324 
00325   /* At this point, no matter what the case was above, we should remove any
00326    * pre-existing unconfirmed record.
00327    */
00328 
00329   punconf = pclient_record->cr_punconfirmed_id;
00330 
00331   if(punconf != NULL)
00332     {
00333       /* CASE 4, replacement of unconfirmed record */
00334 
00335       /* Delete the unconfirmed clientid record */
00336       if(isDebug(COMPONENT_CLIENTID))
00337         {
00338           char str[HASHTABLE_DISPLAY_STRLEN];
00339 
00340           display_client_id_rec(punconf, str);
00341 
00342           LogDebug(COMPONENT_CLIENTID,
00343                    "Replacing %s",
00344                    str);
00345         }
00346 
00347       /* unhash the clientid record */
00348       remove_unconfirmed_client_id(punconf);
00349     }
00350 
00351   /* Now we can proceed to build the new unconfirmed record. We have determined
00352    * the clientid and setclientid_confirm values above.
00353    */
00354 
00355   punconf = create_client_id(0,
00356                              pclient_record,
00357                              &client_addr,
00358                              &data->credential);
00359 
00360   if(punconf == NULL)
00361     {
00362       /* Error already logged, return */
00363       res_EXCHANGE_ID4.eir_status = NFS4ERR_RESOURCE;
00364 
00365       goto out;
00366     }
00367 
00368   memcpy(punconf->cid_incoming_verifier,
00369          arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
00370          NFS4_VERIFIER_SIZE);
00371 
00372   if(gethostname(punconf->cid_server_owner,
00373                  sizeof(punconf->cid_server_owner)) == -1)
00374     {
00375       /* Free the clientid record and return */
00376       free_client_id(punconf);
00377 
00378       res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
00379 
00380       goto out;
00381     }
00382 
00383   snprintf(punconf->cid_server_scope,
00384            sizeof(punconf->cid_server_scope),
00385            "%s_NFS-Ganesha",
00386            punconf->cid_server_owner);
00387 
00388   rc = nfs_client_id_insert(punconf);
00389 
00390   if(rc != CLIENT_ID_SUCCESS)
00391     {
00392       /* Record is already freed, return. */
00393       if(rc == CLIENT_ID_INSERT_MALLOC_ERROR)
00394         res_EXCHANGE_ID4.eir_status = NFS4ERR_RESOURCE;
00395       else
00396         res_EXCHANGE_ID4.eir_status = NFS4ERR_SERVERFAULT;
00397 
00398       goto out;
00399     }
00400 
00401  return_ok:
00402 
00403   /* Build the reply */
00404   res_EXCHANGE_ID4_ok.eir_clientid   = punconf->cid_clientid;
00405   res_EXCHANGE_ID4_ok.eir_sequenceid = punconf->cid_create_session_sequence;
00406 #if defined(_USE_FSALMDS) && defined(_USE_FSALDS)
00407   res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
00408                                   EXCHGID4_FLAG_USE_PNFS_DS |
00409                                   EXCHGID4_FLAG_SUPP_MOVED_REFER;
00410 #elif defined(_USE_FSALMDS)
00411   res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
00412                                   EXCHGID4_FLAG_SUPP_MOVED_REFER;
00413 #elif defined(_USE_FSALDS)
00414   res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_DS |
00415                                   EXCHGID4_FLAG_SUPP_MOVED_REFER;
00416 #elif defined(_USE_DS)
00417   res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_PNFS_MDS |
00418                                   EXCHGID4_FLAG_USE_PNFS_DS |
00419                                   EXCHGID4_FLAG_SUPP_MOVED_REFER;
00420 #else
00421   res_EXCHANGE_ID4_ok.eir_flags = EXCHGID4_FLAG_USE_NON_PNFS |
00422                                   EXCHGID4_FLAG_SUPP_MOVED_REFER;
00423 #endif
00424 
00425   res_EXCHANGE_ID4_ok.eir_state_protect.spr_how = SP4_NONE;
00426 
00427   len  = strlen(punconf->cid_server_owner);
00428   temp = gsh_malloc(len);
00429   if(temp == NULL)
00430     {
00431       LogDebug(component,
00432                "Could not allocate memory for so_major_id in response");
00434       len = 0;
00435     }
00436   else
00437     memcpy(temp, punconf->cid_server_owner, len);
00438 
00439   res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_len = len;
00440   res_EXCHANGE_ID4_ok.eir_server_owner.so_major_id.so_major_id_val = temp;
00441   res_EXCHANGE_ID4_ok.eir_server_owner.so_minor_id = 0;
00442 
00443   len  = strlen(punconf->cid_server_scope);
00444   temp = gsh_malloc(len);
00445   if(temp == NULL)
00446     {
00447       LogDebug(component,
00448                "Could not allocate memory for eir_server_scope in response");
00450       len = 0;
00451     }
00452   else
00453     memcpy(temp, punconf->cid_server_scope, len);
00454 
00455   res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_len = len;
00456   res_EXCHANGE_ID4_ok.eir_server_scope.eir_server_scope_val = temp;
00457 
00458   res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_len = 0;
00459   res_EXCHANGE_ID4_ok.eir_server_impl_id.eir_server_impl_id_val = NULL;
00460 
00461   if(isDebug(COMPONENT_CLIENTID))
00462     {
00463       char str[HASHTABLE_DISPLAY_STRLEN];
00464 
00465       sprint_mem(str_verifier,
00466                  arg_EXCHANGE_ID4.eia_clientowner.co_verifier,
00467                  NFS4_VERIFIER_SIZE);
00468 
00469       display_client_id_rec(punconf, str);
00470 
00471       LogDebug(COMPONENT_CLIENTID,
00472                "EXCHANGE_ID reply Verifier=%s %s",
00473                str_verifier, str);
00474     }
00475 
00476   res_EXCHANGE_ID4.eir_status = NFS4_OK;
00477 
00478  out:
00479 
00480   V(pclient_record->cr_mutex);
00481 
00482   /* Release our reference to the client record */
00483   dec_client_record_ref(pclient_record);
00484 
00485   return res_EXCHANGE_ID4.eir_status;
00486 }                               /* nfs41_op_exchange_id */
00487 
00498 void nfs41_op_exchange_id_Free(EXCHANGE_ID4res * resp)
00499 {
00500   if(resp->eir_status == NFS4_OK)
00501     {
00502       if(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_scope.eir_server_scope_val != NULL)
00503         gsh_free(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_scope.eir_server_scope_val);
00504       if(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_major_id.so_major_id_val != NULL)
00505         gsh_free(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_owner.so_major_id.so_major_id_val);
00506       if(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_impl_id.eir_server_impl_id_val != NULL)
00507         gsh_free(resp->EXCHANGE_ID4res_u.eir_resok4.eir_server_impl_id.eir_server_impl_id_val);
00508     }
00509   return;
00510 }                               /* nfs41_op_exchange_id_Free */