nfs-ganesha 1.4

nfs4_op_setclientid_confirm.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 "nfs_core.h"
00047 #include "sal_functions.h"
00048 #include "nfs_proto_functions.h"
00049 
00066 int nfs4_op_setclientid_confirm(struct nfs_argop4 * op,
00067                                 compound_data_t   * data,
00068                                 struct nfs_resop4 * resp)
00069 {
00070   nfs_client_id_t     * pconf   = NULL;
00071   nfs_client_id_t     * punconf = NULL;
00072   nfs_client_record_t * pclient_record;
00073   clientid4             clientid = 0;
00074   sockaddr_t            client_addr;
00075   char                  str_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
00076   char                  str_client_addr[SOCK_NAME_MAX];
00077   char                  str_client[NFS4_OPAQUE_LIMIT * 2 + 1];
00078   int                   rc;
00079 
00080 #define arg_SETCLIENTID_CONFIRM4 op->nfs_argop4_u.opsetclientid_confirm
00081 #define res_SETCLIENTID_CONFIRM4 resp->nfs_resop4_u.opsetclientid_confirm
00082 
00083   resp->resop                     = NFS4_OP_SETCLIENTID_CONFIRM;
00084   res_SETCLIENTID_CONFIRM4.status = NFS4_OK;
00085   clientid                        = arg_SETCLIENTID_CONFIRM4.clientid;
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       sprint_mem(str_verifier,
00094                  arg_SETCLIENTID_CONFIRM4.setclientid_confirm,
00095                  NFS4_VERIFIER_SIZE);
00096     }
00097 
00098   LogDebug(COMPONENT_CLIENTID,
00099            "SETCLIENTID_CONFIRM client addr=%s clientid=%"PRIx64" setclientid_confirm=%s",
00100            str_client_addr,
00101            clientid,
00102            str_verifier);
00103 
00104   /* First try to look up unconfirmed record */
00105   rc = nfs_client_id_get_unconfirmed(clientid, &punconf);
00106 
00107   if(rc == CLIENT_ID_SUCCESS)
00108     {
00109       pclient_record = punconf->cid_client_record;
00110 
00111       if(isFullDebug(COMPONENT_CLIENTID))
00112         {
00113           char str[HASHTABLE_DISPLAY_STRLEN];
00114 
00115           display_client_id_rec(punconf, str);
00116           LogFullDebug(COMPONENT_CLIENTID,
00117                        "Found %s",
00118                        str);
00119         }
00120     }
00121   else
00122     {
00123       rc = nfs_client_id_get_confirmed(clientid, &pconf);
00124 
00125       if(rc != CLIENT_ID_SUCCESS)
00126         {
00127           /* No record whatsoever of this clientid */
00128           LogDebug(COMPONENT_CLIENTID,
00129                    "Stale clientid = %"PRIx64,
00130                    clientid);
00131           res_SETCLIENTID_CONFIRM4.status = NFS4ERR_STALE_CLIENTID;
00132 
00133           return res_SETCLIENTID_CONFIRM4.status;
00134         }
00135 
00136       pclient_record = pconf->cid_client_record;
00137 
00138       if(isFullDebug(COMPONENT_CLIENTID))
00139         {
00140           char str[HASHTABLE_DISPLAY_STRLEN];
00141 
00142           display_client_id_rec(pconf, str);
00143           LogFullDebug(COMPONENT_CLIENTID,
00144                        "Found %s",
00145                        str);
00146         }
00147     }
00148 
00149   P(pclient_record->cr_mutex);
00150 
00151   inc_client_record_ref(pclient_record);
00152 
00153   if(isFullDebug(COMPONENT_CLIENTID))
00154     {
00155       char str[HASHTABLE_DISPLAY_STRLEN];
00156 
00157       display_client_record(pclient_record, str);
00158 
00159       LogFullDebug(COMPONENT_CLIENTID,
00160                    "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p",
00161                    str,
00162                    pclient_record->cr_pconfirmed_id,
00163                    pclient_record->cr_punconfirmed_id);
00164     }
00165 
00166   /* At this point one and only one of pconf and punconf is non-NULL */
00167 
00168   if(punconf != NULL)
00169     {
00170       /* First must match principal */
00171       if(!nfs_compare_clientcred(&punconf->cid_credential, &data->credential) ||
00172          !cmp_sockaddr(&punconf->cid_client_addr, &client_addr, IGNORE_PORT))
00173         {
00174           if(isDebug(COMPONENT_CLIENTID))
00175             {
00176               char unconfirmed_addr[SOCK_NAME_MAX];
00177 
00178               sprint_sockip(&punconf->cid_client_addr, unconfirmed_addr, sizeof(unconfirmed_addr));
00179 
00180               LogDebug(COMPONENT_CLIENTID,
00181                        "Unconfirmed ClientId %"PRIx64"->'%s': Principals do not match... unconfirmed addr=%s Return NFS4ERR_CLID_INUSE",
00182                        clientid, str_client_addr, unconfirmed_addr);
00183             }
00184 
00185           res_SETCLIENTID_CONFIRM4.status = NFS4ERR_CLID_INUSE;
00186 
00187           dec_client_id_ref(punconf);
00188 
00189           goto out;
00190         }
00191       else if(punconf->cid_confirmed == CONFIRMED_CLIENT_ID &&
00192               memcmp(punconf->cid_verifier,
00193                      arg_SETCLIENTID_CONFIRM4.setclientid_confirm,
00194                      NFS4_VERIFIER_SIZE) == 0)
00195         {
00196           /* We must have raced with another SETCLIENTID_CONFIRM */
00197           if(isDebug(COMPONENT_CLIENTID))
00198             {
00199               char str[HASHTABLE_DISPLAY_STRLEN];
00200 
00201               display_client_id_rec(punconf, str);
00202               LogDebug(COMPONENT_CLIENTID,
00203                        "Race against confirm for %s",
00204                        str);
00205             }
00206 
00207           res_SETCLIENTID_CONFIRM4.status = NFS4_OK;
00208 
00209           dec_client_id_ref(punconf);
00210 
00211           goto out;
00212         }
00213       else if(punconf->cid_confirmed != UNCONFIRMED_CLIENT_ID)
00214         {
00215           /* We raced with another thread that dealt with this unconfirmed record.
00216            * Release our reference, and pretend we didn't find a record.
00217            */
00218           if(isDebug(COMPONENT_CLIENTID))
00219             {
00220               char str[HASHTABLE_DISPLAY_STRLEN];
00221 
00222               display_client_id_rec(punconf, str);
00223 
00224               LogDebug(COMPONENT_CLIENTID,
00225                        "Race against expire for %s",
00226                        str);
00227             }
00228 
00229           res_SETCLIENTID_CONFIRM4.status = NFS4ERR_STALE_CLIENTID;
00230 
00231           dec_client_id_ref(punconf);
00232 
00233           goto out;
00234         }
00235     }
00236 
00237   if(pconf != NULL)
00238     {
00239       if(isDebug(COMPONENT_CLIENTID) && pconf != NULL)
00240         display_clientid_name(pconf, str_client);
00241 
00242       /* First must match principal */
00243       if(!nfs_compare_clientcred(&pconf->cid_credential, &data->credential) ||
00244          !cmp_sockaddr(&pconf->cid_client_addr, &client_addr, IGNORE_PORT))
00245         {
00246           if(isDebug(COMPONENT_CLIENTID))
00247             {
00248               char confirmed_addr[SOCK_NAME_MAX];
00249 
00250               sprint_sockip(&pconf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr));
00251 
00252               LogDebug(COMPONENT_CLIENTID,
00253                        "Confirmed ClientId %"PRIx64"->%s addr=%s: Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE",
00254                        clientid, str_client, str_client_addr, confirmed_addr);
00255             }
00256 
00257           res_SETCLIENTID_CONFIRM4.status = NFS4ERR_CLID_INUSE;
00258         }
00259       else if(memcmp(pconf->cid_verifier,
00260                      arg_SETCLIENTID_CONFIRM4.setclientid_confirm,
00261                      NFS4_VERIFIER_SIZE) == 0)
00262         {
00263           /* In this case, the record was confirmed and we have received a retry */
00264           if(isDebug(COMPONENT_CLIENTID))
00265             {
00266               char str[HASHTABLE_DISPLAY_STRLEN];
00267 
00268               display_client_id_rec(pconf, str);
00269               LogDebug(COMPONENT_CLIENTID,
00270                        "Retry confirm for %s",
00271                        str);
00272             }
00273 
00274           res_SETCLIENTID_CONFIRM4.status = NFS4_OK;
00275         }
00276       else
00277         {
00278           /* This is a case not covered... Return NFS4ERR_CLID_INUSE */
00279           if(isDebug(COMPONENT_CLIENTID))
00280             {
00281               char str[HASHTABLE_DISPLAY_STRLEN];
00282               char str_conf_verifier[NFS4_VERIFIER_SIZE * 2 + 1];
00283 
00284               sprint_mem(str_conf_verifier,
00285                          pconf->cid_verifier,
00286                          NFS4_VERIFIER_SIZE);
00287 
00288               display_client_id_rec(pconf, str);
00289 
00290               LogDebug(COMPONENT_CLIENTID,
00291                        "Confirm verifier=%s doesn't match verifier=%s for %s",
00292                        str_conf_verifier, str_verifier, str);
00293             }
00294 
00295           res_SETCLIENTID_CONFIRM4.status = NFS4ERR_CLID_INUSE;
00296         }
00297 
00298       /* Release our reference to the confirmed clientid. */
00299       dec_client_id_ref(pconf);
00300 
00301       goto out;
00302     }
00303 
00304   /* We don't need to do any further principal checks, we can't have a confirmed
00305    * clientid record with a different principal than the unconfirmed record.
00306    * Also, at this point, we have a matching unconfirmed clientid
00307    * (punconf != NULL and pconf == NULL).
00308    */
00309 
00310   /* Make sure we have a reference to the confirmed clientid record if any */
00311   if(pconf == NULL)
00312     {
00313       pconf = pclient_record->cr_pconfirmed_id;
00314 
00315       if(isDebug(COMPONENT_CLIENTID) && pconf != NULL)
00316         display_clientid_name(pconf, str_client);
00317 
00318       /* Need a reference to the confirmed record for below */
00319       if(pconf != NULL)
00320         inc_client_id_ref(pconf);
00321     }
00322 
00323   if(pconf != NULL && pconf->cid_clientid != clientid)
00324     {
00325       /* Old confirmed record - need to expire it */
00326       if(isDebug(COMPONENT_CLIENTID))
00327         {
00328           char str[HASHTABLE_DISPLAY_STRLEN];
00329 
00330           display_client_id_rec(pconf, str);
00331           LogDebug(COMPONENT_CLIENTID,
00332                    "Expiring %s",
00333                    str);
00334         }
00335 
00336       /* Expire clientid and release our reference. */
00337       nfs_client_id_expire(pconf);
00338 
00339       dec_client_id_ref(pconf);
00340 
00341       pconf = NULL;
00342     }
00343 
00344   if(pconf != NULL)
00345     {
00346       /* At this point we are updating the confirmed clientid.
00347        * Update the confirmed record from the unconfirmed record.
00348        */
00349       if(isFullDebug(COMPONENT_CLIENTID))
00350         {
00351           char str[HASHTABLE_DISPLAY_STRLEN];
00352 
00353           display_client_id_rec(punconf, str);
00354           LogFullDebug(COMPONENT_CLIENTID,
00355                        "Updating from %s",
00356                        str);
00357         }
00358 
00359       /* Copy callback information into confirmed clientid record */
00360       memcpy(pconf->cid_cb.cid_client_r_addr,
00361              punconf->cid_cb.cid_client_r_addr,
00362              sizeof(pconf->cid_cb.cid_client_r_addr));
00363 
00364       pconf->cid_cb.cid_addr    = punconf->cid_cb.cid_addr;
00365       pconf->cid_cb.cid_program = punconf->cid_cb.cid_program;
00366 
00367       pconf->cid_cb.cb_u.v40.cb_callback_ident =
00368         punconf->cid_cb.cb_u.v40.cb_callback_ident;
00369 
00370       nfs_rpc_destroy_chan(&pconf->cid_cb.cb_u.v40.cb_chan);
00371 
00372       memcpy(pconf->cid_verifier, punconf->cid_verifier, NFS4_VERIFIER_SIZE);
00373 
00374       /* unhash the unconfirmed clientid record */
00375       remove_unconfirmed_client_id(punconf);
00376 
00377       /* Release our reference to the unconfirmed entry */
00378       dec_client_id_ref(punconf);
00379 
00380       if(isDebug(COMPONENT_CLIENTID))
00381         {
00382           char str[HASHTABLE_DISPLAY_STRLEN];
00383 
00384           display_client_id_rec(pconf, str);
00385           LogDebug(COMPONENT_CLIENTID,
00386                    "Updated %s",
00387                    str);
00388         }
00389 
00390       /* Release our reference to the confirmed clientid. */
00391       dec_client_id_ref(pconf);
00392     }
00393   else
00394     {
00395       /* This is a new clientid */
00396       if(isFullDebug(COMPONENT_CLIENTID))
00397         {
00398           char str[HASHTABLE_DISPLAY_STRLEN];
00399 
00400           display_client_id_rec(punconf, str);
00401 
00402           LogFullDebug(COMPONENT_CLIENTID,
00403                        "Confirming new %s",
00404                        str);
00405         }
00406 
00407       rc = nfs_client_id_confirm(punconf, COMPONENT_CLIENTID);
00408 
00409       if(rc != CLIENT_ID_SUCCESS)
00410         {
00411           if(rc == CLIENT_ID_INVALID_ARGUMENT)
00412             res_SETCLIENTID_CONFIRM4.status = NFS4ERR_SERVERFAULT;
00413           else
00414             res_SETCLIENTID_CONFIRM4.status = NFS4ERR_RESOURCE;
00415 
00416           /* Release our reference to the unconfirmed record */
00417           dec_client_id_ref(punconf);
00418 
00419           goto out;
00420         }
00421 
00422       /*
00423        * We have successfully added a new confirmed client id.  Now
00424        * add it to stable storage.
00425        */
00426       nfs4_create_clid_name(pclient_record, punconf, data->reqp);
00427       nfs4_add_clid(punconf);
00428 
00429       /* check if the client can perform reclaims */
00430       nfs4_chk_clid(punconf);
00431 
00432       if(isDebug(COMPONENT_CLIENTID))
00433         {
00434           char str[HASHTABLE_DISPLAY_STRLEN];
00435 
00436           display_client_id_rec(punconf, str);
00437 
00438           LogDebug(COMPONENT_CLIENTID,
00439                    "Confirmed %s",
00440                    str);
00441         }
00442 
00443       /* Release our reference to the now confirmed record */
00444       dec_client_id_ref(punconf);
00445     }
00446 
00447   if(isFullDebug(COMPONENT_CLIENTID))
00448     {
00449       char str[HASHTABLE_DISPLAY_STRLEN];
00450 
00451       display_client_record(pclient_record, str);
00452 
00453       LogFullDebug(COMPONENT_CLIENTID,
00454                    "Client Record %s cr_pconfirmed_id=%p cr_punconfirmed_id=%p",
00455                    str,
00456                    pclient_record->cr_pconfirmed_id,
00457                    pclient_record->cr_punconfirmed_id);
00458     }
00459 
00460   /* Successful exit */
00461   res_SETCLIENTID_CONFIRM4.status = NFS4_OK;
00462 
00463  out:
00464 
00465   V(pclient_record->cr_mutex);
00466 
00467   /* Release our reference to the client record and return */
00468   dec_client_record_ref(pclient_record);
00469 
00470   return res_SETCLIENTID_CONFIRM4.status;
00471 }                               /* nfs4_op_setclientid_confirm */
00472 
00483 void nfs4_op_setclientid_confirm_Free(SETCLIENTID_CONFIRM4res * resp)
00484 {
00485   /* To be completed */
00486   return;
00487 }                               /* nfs4_op_setclientid_confirm_Free */