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