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 "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 */