nfs-ganesha 1.4

mnt_Mnt.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
00011  * License as published by the Free Software Foundation; either
00012  * version 3 of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but 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  02110-1301  USA
00022  * 
00023  * ---------------------------------------
00024  */
00025 
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039 
00040 #ifdef _SOLARIS
00041 #include "solaris_port.h"
00042 #endif
00043 
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <pthread.h>
00047 #include <fcntl.h>
00048 #include <sys/file.h>           /* for having FNDELAY */
00049 #include "HashData.h"
00050 #include "HashTable.h"
00051 #include "log.h"
00052 #include "nfs23.h"
00053 #include "nfs4.h"
00054 #include "nfs_core.h"
00055 #include "cache_inode.h"
00056 #include "nfs_exports.h"
00057 #include "nfs_creds.h"
00058 #include "nfs_tools.h"
00059 #include "mount.h"
00060 #include "nfs_proto_functions.h"
00061 #include "nfs_proto_tools.h"
00062 
00077 int mnt_Mnt(nfs_arg_t *parg,
00078             exportlist_t *pexport,
00079             fsal_op_context_t *pcontext,
00080             nfs_worker_data_t *pworker,
00081             struct svc_req *preq,
00082             nfs_res_t *pres)
00083 {
00084 
00085   char exportPath[MNTPATHLEN + 1];
00086   exportlist_t *p_current_item;
00087 
00088   fsal_handle_t pfsal_handle;
00089 
00090   int auth_flavor[NB_AUTH_FLAVOR];
00091   int index_auth = 0;
00092   int i = 0;
00093 
00094   char exported_path[MAXPATHLEN];
00095   char tmplist_path[MAXPATHLEN];
00096   char tmpexport_path[MAXPATHLEN];
00097   char *hostname;
00098   fsal_path_t fsal_path;
00099   unsigned int bytag = FALSE;
00100 
00101   LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling mnt_Mnt path=%s",
00102            parg->arg_mnt);
00103 
00104   /* Paranoid command to clean the result struct. */
00105   memset(pres, 0, sizeof(nfs_res_t));
00106 
00107   if(parg->arg_mnt == NULL)
00108     {
00109       LogCrit(COMPONENT_NFSPROTO,
00110               "MOUNT: NULL path passed as Mount argument !!!");
00111       return NFS_REQ_DROP;
00112     }
00113 
00114   /* Retrieving arguments */
00115   strncpy(exportPath, parg->arg_mnt, MNTPATHLEN + 1);
00116 
00117   /*
00118    * Find the export for the dirname (using as well Path or Tag ) 
00119    */
00120   for(p_current_item = pexport; p_current_item != NULL;
00121       p_current_item = p_current_item->next)
00122     {
00123       if(exportPath[0] != '/')
00124         {
00125           /* The input value may be a "Tag" */
00126           if(!strcmp(exportPath, p_current_item->FS_tag))
00127             {
00128               strncpy(exported_path, p_current_item->fullpath, MAXPATHLEN);
00129               bytag = TRUE;
00130               break;
00131             }
00132         }
00133       else
00134         {
00135           /* Make sure the path in export entry ends with a '/', if not adds one */
00136           if(p_current_item->fullpath[strlen(p_current_item->fullpath) - 1] == '/')
00137             strncpy(tmplist_path, p_current_item->fullpath, MAXPATHLEN);
00138           else
00139             snprintf(tmplist_path, MAXPATHLEN, "%s/", p_current_item->fullpath);
00140 
00141           /* Make sure that the argument from MNT ends with a '/', if not adds one */
00142           if(exportPath[strlen(exportPath) - 1] == '/')
00143             strncpy(tmpexport_path, exportPath, MAXPATHLEN);
00144           else
00145             snprintf(tmpexport_path, MAXPATHLEN, "%s/", exportPath);
00146 
00147           /* Is tmplist_path a subdirectory of tmpexport_path ? */
00148           if(!strncmp(tmplist_path, tmpexport_path, strlen(tmplist_path)))
00149             {
00150               strncpy(exported_path, p_current_item->fullpath, MAXPATHLEN);
00151               break;
00152             }
00153         }
00154     }
00155 
00156   /* if p_current_item is not null,
00157    * it points to the asked export entry.
00158    */
00159 
00160   if(!p_current_item)
00161     {
00162       LogCrit(COMPONENT_NFSPROTO, "MOUNT: Export entry %s not found",
00163               exportPath);
00164 
00165       /* entry not found. */
00166       /* @todo : not MNT3ERR_NOENT => ok */
00167       switch (preq->rq_vers)
00168         {
00169         case MOUNT_V1:
00170           pres->res_mnt1.status = NFSERR_ACCES;
00171           break;
00172 
00173         case MOUNT_V3:
00174           pres->res_mnt3.fhs_status = MNT3ERR_ACCES;
00175           break;
00176         }
00177       return NFS_REQ_OK;
00178     }
00179 
00180   LogDebug(COMPONENT_NFSPROTO,
00181            "MOUNT: Export entry Path=%s Tag=%s matches %s, export_id=%u",
00182            exported_path, p_current_item->FS_tag, exportPath,
00183            p_current_item->id);
00184 
00185   /* @todo : check wether mount is allowed.
00186    *  to do so, retrieve client identifier from the credential.
00187    */
00188 
00189   switch (preq->rq_vers)
00190     {
00191     case MOUNT_V1:
00192       if((p_current_item->options & EXPORT_OPTION_NFSV2) != 0)
00193         break;
00194       pres->res_mnt1.status = NFSERR_ACCES;
00195       return NFS_REQ_OK;
00196 
00197     case MOUNT_V3:
00198       if((p_current_item->options & EXPORT_OPTION_NFSV3) != 0)
00199         break;
00200       pres->res_mnt3.fhs_status = MNT3ERR_ACCES;
00201       return NFS_REQ_OK;
00202     }
00203   
00204 
00205   /*
00206    * retrieve the associated NFS handle
00207    */
00208 
00209   pfsal_handle = *p_current_item->proot_handle;
00210   if(!(bytag == TRUE || !strncmp(tmpexport_path, tmplist_path, MAXPATHLEN)))
00211     {
00212       if(FSAL_IS_ERROR(FSAL_str2path(tmpexport_path, MAXPATHLEN, &fsal_path)))
00213         {
00214           switch (preq->rq_vers)
00215             {
00216             case MOUNT_V1:
00217               pres->res_mnt1.status = NFSERR_IO;
00218               break;
00219 
00220             case MOUNT_V3:
00221               pres->res_mnt3.fhs_status = MNT3ERR_IO;
00222               break;
00223             }
00224           return NFS_REQ_OK;
00225         }
00226 
00227       LogEvent(COMPONENT_NFSPROTO,
00228                "MOUNT: Performance warning: Export entry is not cached");
00229       if(FSAL_IS_ERROR(FSAL_lookupPath(&fsal_path, pcontext, &pfsal_handle, NULL)))
00230         {
00231           switch (preq->rq_vers)
00232             {
00233             case MOUNT_V1:
00234               pres->res_mnt1.status = NFSERR_ACCES;
00235               break;
00236 
00237             case MOUNT_V3:
00238               pres->res_mnt3.fhs_status = MNT3ERR_ACCES;
00239               break;
00240             }
00241           return NFS_REQ_OK;
00242         }
00243 
00244     }
00245   /* convert the fsal_handle to a file handle */
00246   switch (preq->rq_vers)
00247     {
00248     case MOUNT_V1:
00249       if(!nfs2_FSALToFhandle(&(pres->res_mnt1.fhstatus2_u.directory),
00250                              &pfsal_handle, p_current_item))
00251         {
00252           pres->res_mnt1.status = NFSERR_IO;
00253         }
00254       else
00255         {
00256           pres->res_mnt1.status = NFS_OK;
00257         }
00258       break;
00259 
00260     case MOUNT_V3:
00261 /* FIXME: The mountinfo.fhandle definition is an overlay on/of nfs_fh3.
00262  * redefine and eliminate one or the other.
00263  */
00264       pres->res_mnt3.fhs_status =
00265               nfs3_AllocateFH((nfs_fh3 *) &pres->res_mnt3.mountres3_u.mountinfo.fhandle);
00266       if(pres->res_mnt3.fhs_status ==  MNT3_OK)
00267         {
00268           if(!nfs3_FSALToFhandle
00269              ((nfs_fh3 *) & (pres->res_mnt3.mountres3_u.mountinfo.fhandle), &pfsal_handle,
00270               p_current_item))
00271             {
00272               pres->res_mnt3.fhs_status = MNT3ERR_INVAL;
00273             }
00274           else
00275             {
00276               pres->res_mnt3.fhs_status = MNT3_OK;
00277 
00278               /* Auth et nfs_SetPostOpAttr ici */
00279             }
00280         }
00281 
00282       break;
00283     }
00284 
00285   /* Return the supported authentication flavor in V3 */
00286   if(preq->rq_vers == MOUNT_V3)
00287     {
00288       if(p_current_item->options & EXPORT_OPTION_AUTH_NONE)
00289         auth_flavor[index_auth++] = AUTH_NONE;
00290       if(p_current_item->options & EXPORT_OPTION_AUTH_UNIX)
00291         auth_flavor[index_auth++] = AUTH_UNIX;
00292 #ifdef _HAVE_GSSAPI
00293       if(nfs_param.krb5_param.active_krb5 == TRUE)
00294         {
00295           if(p_current_item->options & EXPORT_OPTION_RPCSEC_GSS_NONE)
00296             auth_flavor[index_auth++] = MNT_RPC_GSS_NONE;
00297           if(p_current_item->options & EXPORT_OPTION_RPCSEC_GSS_INTG)
00298             auth_flavor[index_auth++] = MNT_RPC_GSS_INTEGRITY;
00299           if(p_current_item->options & EXPORT_OPTION_RPCSEC_GSS_PRIV)
00300             auth_flavor[index_auth++] = MNT_RPC_GSS_PRIVACY;
00301         }
00302 #endif
00303 
00304       LogDebug(COMPONENT_NFSPROTO,
00305                "MOUNT: Entry support %d different flavours", index_auth);
00306 
00307 #define RES_MOUNTINFO pres->res_mnt3.mountres3_u.mountinfo
00308       if((RES_MOUNTINFO.auth_flavors.auth_flavors_val =
00309           gsh_calloc(index_auth, sizeof(int))) == NULL)
00310         return NFS_REQ_DROP;
00311 
00312       RES_MOUNTINFO.auth_flavors.auth_flavors_len = index_auth;
00313       for(i = 0; i < index_auth; i++)
00314         RES_MOUNTINFO.auth_flavors.auth_flavors_val[i] = auth_flavor[i];
00315     }
00316 
00317   /* Add the client to the mount list */
00318   /* @todo: BUGAZOMEU; seul AUTHUNIX est supporte */
00319   hostname = ((struct authunix_parms *)(preq->rq_clntcred))->aup_machname;
00320 
00321   if(!nfs_Add_MountList_Entry(hostname, exportPath))
00322     {
00323       LogCrit(COMPONENT_NFSPROTO,
00324               "MOUNT: Error when adding entry (%s,%s) to the mount list, Mount command will be successfull anyway",
00325               hostname, exportPath);
00326     }
00327   else
00328     LogFullDebug(COMPONENT_NFSPROTO,
00329                  "MOUNT: mount list entry (%s,%s) added", hostname, exportPath);
00330 
00331   return NFS_REQ_OK;
00332 
00333 }                               /* mnt_Mnt */
00334 
00344 void mnt1_Mnt_Free(nfs_res_t * pres)
00345 {
00346   return;
00347 }                               /* mnt_Mnt_Free */
00348 
00349 void mnt3_Mnt_Free(nfs_res_t * pres)
00350 {
00351   if(pres->res_mnt3.fhs_status == MNT3_OK)
00352     {
00353       gsh_free(pres->res_mnt3.mountres3_u.mountinfo.
00354                auth_flavors.auth_flavors_val);
00355       gsh_free(pres->res_mnt3.mountres3_u.mountinfo.fhandle.fhandle3_val);
00356     }
00357   return;
00358 }                               /* mnt_Mnt_Free */