nfs-ganesha 1.4
|
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 */