nfs-ganesha 1.4

nfs_export_list.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 
00079 #ifdef HAVE_CONFIG_H
00080 #include "config.h"
00081 #endif
00082 
00083 #ifdef _SOLARIS
00084 #include "solaris_port.h"
00085 #endif
00086 
00087 #include <stdio.h>
00088 #include <sys/types.h>
00089 #include <ctype.h>              /* for having isalnum */
00090 #include <stdlib.h>             /* for having atoi */
00091 #include <dirent.h>             /* for having MAXNAMLEN */
00092 #include <netdb.h>
00093 #include <netinet/in.h>
00094 #include <arpa/inet.h>
00095 #include <string.h>
00096 #include <pthread.h>
00097 #include <fcntl.h>
00098 #include <sys/file.h>           /* for having FNDELAY */
00099 #include <pwd.h>
00100 #include <grp.h>
00101 #include "log.h"
00102 #include "ganesha_rpc.h"
00103 #include "nfs_core.h"
00104 #include "nfs23.h"
00105 #include "nfs4.h"
00106 #include "fsal.h"
00107 #include "nfs_tools.h"
00108 #include "nfs_exports.h"
00109 #include "nfs_file_handle.h"
00110 
00111 const char *Rpc_gss_svc_name[] =
00112     { "no name", "RPCSEC_GSS_SVC_NONE", "RPCSEC_GSS_SVC_INTEGRITY",
00113   "RPCSEC_GSS_SVC_PRIVACY"
00114 };
00115 
00128 exportlist_t *nfs_Get_export_by_id(exportlist_t * exportroot, unsigned short exportid)
00129 {
00130   exportlist_t *piter;
00131   int found = 0;
00132 
00133   for(piter = exportroot; piter != NULL; piter = piter->next)
00134     {
00135       if(piter->id == exportid)
00136         {
00137           found = 1;
00138           break;
00139         }
00140     }                           /* for */
00141 
00142   if(found == 0)
00143     return NULL;
00144   else
00145     return piter;
00146 }                               /* nfs_Get_export_by_id */
00147 
00162 int get_req_uid_gid(struct svc_req *req,
00163                     exportlist_t * pexport,
00164                     struct user_cred *user_credentials)
00165 {
00166   struct authunix_parms *punix_creds = NULL;
00167 #ifdef _HAVE_GSSAPI
00168   struct svc_rpc_gss_data *gd = NULL;
00169   char principal[MAXNAMLEN];
00170 #endif
00171 
00172   if (user_credentials == NULL)
00173     return FALSE;
00174 
00175   switch (req->rq_cred.oa_flavor)
00176     {
00177     case AUTH_NONE:
00178       /* Nothing to be done here... */
00179       LogFullDebug(COMPONENT_DISPATCH,
00180                    "Request xid=%u has authentication AUTH_NONE",
00181                    req->rq_xid);
00182       user_credentials->caller_uid = pexport->anonymous_uid;
00183       user_credentials->caller_gid = pexport->anonymous_gid;
00184       user_credentials->caller_glen = 0;
00185       user_credentials->caller_garray = NULL;
00186       break;
00187 
00188     case AUTH_UNIX:
00189       LogFullDebug(COMPONENT_DISPATCH,
00190                    "Request xid=%u has authentication AUTH_UNIX",
00191                    req->rq_xid);
00192       /* We map the rq_cred to Authunix_parms */
00193       punix_creds = (struct authunix_parms *) req->rq_clntcred;
00194 
00195       /* Get the uid/gid couple */
00196       user_credentials->caller_uid = punix_creds->aup_uid;
00197       user_credentials->caller_gid = punix_creds->aup_gid;
00198       user_credentials->caller_glen = punix_creds->aup_len;
00199       user_credentials->caller_garray = punix_creds->aup_gids;
00200 
00201       LogFullDebug(COMPONENT_DISPATCH, "----> Uid=%u Gid=%u",
00202                    (unsigned int)user_credentials->caller_uid,
00203                    (unsigned int)user_credentials->caller_gid);
00204 
00205       break;
00206 
00207 #ifdef _HAVE_GSSAPI
00208     case RPCSEC_GSS:
00209       LogFullDebug(COMPONENT_DISPATCH,
00210                    "Request xid=%u has authentication RPCSEC_GSS",
00211                    req->rq_xid);
00212       /* Get the gss data to process them */
00213       gd = SVCAUTH_PRIVATE(req->rq_xprt->xp_auth);
00214 
00215       if(isFullDebug(COMPONENT_RPCSEC_GSS))
00216         {
00217           OM_uint32 maj_stat = 0;
00218           OM_uint32 min_stat = 0;
00219           char ptr[256];
00220 
00221           gss_buffer_desc oidbuff;
00222 
00223           LogFullDebug(COMPONENT_RPCSEC_GSS,
00224                        "----> RPCSEC_GSS svc=%u RPCSEC_GSS_SVC_NONE=%u "
00225                        "RPCSEC_GSS_SVC_INTEGRITY=%u RPCSEC_GSS_SVC_PRIVACY=%u",
00226                        gd->sec.svc, RPCSEC_GSS_SVC_NONE,
00227                        RPCSEC_GSS_SVC_INTEGRITY,
00228                        RPCSEC_GSS_SVC_PRIVACY);
00229 
00230           memcpy(&ptr, (void *)gd->ctx + 4, 4);
00231           LogFullDebug(COMPONENT_RPCSEC_GSS,
00232                        "----> Client=%s length=%lu  Qop=%u established=%u "
00233                        "gss_ctx_id=%p|%p",
00234                        (char *)gd->cname.value, gd->cname.length,
00235                        gd->established, gd->sec.qop,
00236                        gd->ctx, ptr);
00237 
00238           if((maj_stat = gss_oid_to_str(
00239                   &min_stat, gd->sec.mech, &oidbuff)) != GSS_S_COMPLETE)
00240             {
00241               LogFullDebug(COMPONENT_DISPATCH, "Error in gss_oid_to_str: %u|%u",
00242                            maj_stat, min_stat);
00243             }
00244           else
00245             {
00246               LogFullDebug(COMPONENT_RPCSEC_GSS, "----> Client mech=%s len=%lu",
00247                            (char *)oidbuff.value, oidbuff.length);
00248 
00249               /* Release the string */
00250               (void)gss_release_buffer(&min_stat, &oidbuff); 
00251             }
00252        }
00253 
00254       LogFullDebug(COMPONENT_RPCSEC_GSS, "Mapping principal %s to uid/gid",
00255                    (char *)gd->cname.value);
00256 
00257       memcpy(principal, gd->cname.value, gd->cname.length);
00258       principal[gd->cname.length] = 0;
00259 
00260       /* Convert to uid */
00261       if(!principal2uid(principal, &user_credentials->caller_uid))
00262         {
00263           LogWarn(COMPONENT_IDMAPPER,
00264                   "WARNING: Could not map principal to uid; mapping principal "
00265                   "to anonymous uid/gid");
00266 
00267           /* For compatibility with Linux knfsd, we set the uid/gid
00268            * to anonymous when a name->uid mapping can't be found. */
00269           user_credentials->caller_uid = pexport->anonymous_uid;
00270           user_credentials->caller_gid = pexport->anonymous_gid;
00271           
00272           /* No alternate groups for "nobody" */
00273           user_credentials->caller_glen = 0 ;
00274           user_credentials->caller_garray = NULL ;
00275 
00276           return TRUE;
00277         }
00278 
00279       if(uidgidmap_get(user_credentials->caller_uid,
00280                        &user_credentials->caller_gid) != ID_MAPPER_SUCCESS)
00281         {
00282           LogMajor(COMPONENT_DISPATCH,
00283                    "FAILURE: Could not resolve uidgid map for %u",
00284                    user_credentials->caller_uid);
00285           user_credentials->caller_gid = -1;
00286         }
00287       LogFullDebug(COMPONENT_DISPATCH, "----> Uid=%u Gid=%u",
00288                    (unsigned int)user_credentials->caller_uid,
00289                    (unsigned int)user_credentials->caller_gid);
00290       user_credentials->caller_glen = 0;
00291       user_credentials->caller_garray = 0;
00292 
00293       break;
00294 #endif                          /* _USE_GSSRPC */
00295 
00296     default:
00297       LogFullDebug(COMPONENT_DISPATCH,
00298                    "FAILURE: Request xid=%u, has unsupported authentication %d",
00299                    req->rq_xid, req->rq_cred.oa_flavor);
00300       /* Reject the request for weak authentication and return to worker */
00301       return FALSE;
00302 
00303       break;
00304     }                           /* switch( req->rq_cred.oa_flavor ) */
00305   return TRUE;
00306 }
00307 
00308 int nfs_check_anon(exportlist_client_entry_t * pexport_client,
00309                    exportlist_t * pexport,
00310                    struct user_cred *user_credentials)
00311 {
00312   if (user_credentials == NULL)
00313     return FALSE;
00314 
00315   /* Do we have root access ? */
00316   /* Are we squashing _all_ users to the anonymous uid/gid ? */
00317   if( ((user_credentials->caller_uid == 0)
00318        && !(pexport_client->options & EXPORT_OPTION_ROOT))
00319       || pexport->all_anonymous == TRUE)
00320     {
00321       user_credentials->caller_uid = pexport->anonymous_uid;
00322       user_credentials->caller_gid = pexport->anonymous_gid;
00323       
00324       /* No alternate groups for "nobody" */
00325       user_credentials->caller_glen = 0 ;
00326       user_credentials->caller_garray = NULL ;
00327     }
00328 
00329   return TRUE;
00330 }
00331 
00348 int nfs_build_fsal_context(struct svc_req *req,
00349                            exportlist_t * pexport,
00350                            fsal_op_context_t * pcontext,
00351                            struct user_cred *user_credentials)
00352 {
00353   fsal_status_t fsal_status;
00354 
00355   if (user_credentials == NULL)
00356     return FALSE;
00357 
00358   /* Build the credentials */
00359   fsal_status = FSAL_GetClientContext(pcontext,
00360                                       &pexport->FS_export_context,
00361                                       user_credentials->caller_uid,
00362                                       user_credentials->caller_gid,
00363                                       user_credentials->caller_garray,
00364                                       user_credentials->caller_glen);
00365 
00366   /*
00367    * TODO: Fix this hack
00368    * This hack put here to pass the IP address to the fsal
00369    * via the fsal_op_context_t->credential.
00370    *
00371    * This a hack because it breaks the fsal API. fsal_op_context_t is an
00372    * fsal specific structure that should only be handled in the fsal
00373    *
00374    * But we do this here because passing the ip through the
00375    * FSAL_GetClientContext parameters requires a lot of code change
00376    *
00377    * The plan is to correct this hack when we roll over to the new
00378    * API where this struct has been made common
00379    */
00380   copy_xprt_addr(&pcontext->credential.caller_addr, req->rq_xprt);
00381 
00382   if(FSAL_IS_ERROR(fsal_status))
00383     {
00384       LogEvent(COMPONENT_DISPATCH,
00385                "NFS DISPATCHER: FAILURE: Could not get credentials for "
00386                "(uid=%d,gid=%d), fsal error=(%d,%d)",
00387                user_credentials->caller_uid, user_credentials->caller_gid,
00388                fsal_status.major, fsal_status.minor);
00389       return FALSE;
00390     }
00391   else
00392     LogDebug(COMPONENT_DISPATCH,
00393              "NFS DISPATCHER: FSAL Cred acquired for (uid=%d,gid=%d)",
00394              user_credentials->caller_uid, user_credentials->caller_gid);
00395 
00396   return TRUE;
00397 }                               /* nfs_build_fsal_context */
00398 
00409 int nfs_compare_clientcred(nfs_client_cred_t * pcred1,
00410                            nfs_client_cred_t *pcred2)
00411 {
00412   if(pcred1 == NULL)
00413     return FALSE;
00414   if(pcred2 == NULL)
00415     return FALSE;
00416 
00417   if(pcred1->flavor != pcred2->flavor)
00418     return FALSE;
00419 
00420   if(pcred1->length != pcred2->length)
00421     return FALSE;
00422 
00423   switch (pcred1->flavor)
00424     {
00425     case AUTH_UNIX:
00426       if(pcred1->auth_union.auth_unix.aup_uid !=
00427          pcred2->auth_union.auth_unix.aup_uid)
00428         return FALSE;
00429       if(pcred1->auth_union.auth_unix.aup_gid !=
00430          pcred2->auth_union.auth_unix.aup_gid)
00431         return FALSE;
00432       if(pcred1->auth_union.auth_unix.aup_time !=
00433          pcred2->auth_union.auth_unix.aup_time)
00434         return FALSE;
00435       break;
00436 
00437     default:
00438       if(memcmp(&pcred1->auth_union, &pcred2->auth_union, pcred1->length))
00439         return FALSE;
00440       break;
00441     }
00442 
00443   /* If this point is reach, structures are the same */
00444   return TRUE;
00445 }                               /* nfs_compare_clientcred */
00446 
00447 int nfs_rpc_req2client_cred(struct svc_req *reqp, nfs_client_cred_t * pcred)
00448 {
00449   /* Structure for managing basic AUTH_UNIX authentication */
00450   struct authunix_parms *aup = NULL;
00451 
00452   /* Stuff needed for managing RPCSEC_GSS */
00453 #ifdef _HAVE_GSSAPI
00454   OM_uint32 maj_stat = 0;
00455   OM_uint32 min_stat = 0;
00456   struct svc_rpc_gss_data *gd = NULL;
00457   gss_buffer_desc oidbuff;
00458 #endif
00459 
00460   if(reqp == NULL || pcred == NULL)
00461     return -1;
00462 
00463   pcred->flavor = reqp->rq_cred.oa_flavor;
00464   pcred->length = reqp->rq_cred.oa_length;
00465 
00466   switch (reqp->rq_cred.oa_flavor)
00467     {
00468     case AUTH_NONE:
00469       /* Do nothing... because there seems like nothing is to be done... */
00470       break;
00471 
00472     case AUTH_UNIX:
00473       aup = (struct authunix_parms *)(reqp->rq_clntcred);
00474 
00475       pcred->auth_union.auth_unix.aup_uid = aup->aup_uid;
00476       pcred->auth_union.auth_unix.aup_gid = aup->aup_gid;
00477       pcred->auth_union.auth_unix.aup_time = aup->aup_time;
00478 
00479       break;
00480 
00481 #ifdef _HAVE_GSSAPI
00482     case RPCSEC_GSS:
00483       /* Extract the information from the RPCSEC_GSS opaque structure */
00484       gd = SVCAUTH_PRIVATE(reqp->rq_xprt->xp_auth);
00485 
00486       pcred->auth_union.auth_gss.svc = (unsigned int)(gd->sec.svc);
00487       pcred->auth_union.auth_gss.qop = (unsigned int)(gd->sec.qop);
00488       pcred->auth_union.auth_gss.gss_context_id = gd->ctx;
00489 
00490       /* XXX */
00491       strncpy(pcred->auth_union.auth_gss.cname, gd->cname.value,
00492               NFS_CLIENT_NAME_LEN);
00493 
00494       if((maj_stat = gss_oid_to_str(
00495               &min_stat, gd->sec.mech, &oidbuff)) != GSS_S_COMPLETE)
00496         {
00497           char errbuff[1024];
00498           log_sperror_gss(errbuff, maj_stat, min_stat);
00499           LogCrit(COMPONENT_DISPATCH,
00500                   "GSSAPI ERROR: %u|%u = %s",
00501                   maj_stat, min_stat, errbuff);
00502           return -1;
00503         }
00504 
00505       /* XXX */
00506       strncpy(pcred->auth_union.auth_gss.stroid, oidbuff.value,
00507               NFS_CLIENT_NAME_LEN);
00508 
00509       /* Je fais le menage derriere moi */
00510       (void)gss_release_buffer(&min_stat, &oidbuff);
00511       break;
00512 #endif
00513 
00514     default:
00515       /* Unsupported authentication flavour */
00516       return -1;
00517       break;
00518     }
00519 
00520   return 1;
00521 }                               /* nfs_rpc_req2client_cred */
00522 
00523 int nfs_export_tag2path(exportlist_t * exportroot, char *tag, int taglen,
00524                         char *path, int pathlen)
00525 {
00526   if(!tag || !path)
00527     return -1;
00528 
00529   exportlist_t *piter;
00530 
00531   for(piter = exportroot; piter != NULL; piter = piter->next)
00532     {
00533       if(!strncmp(tag, piter->FS_tag, taglen))
00534         {
00535           strncpy(path, piter->fullpath, pathlen);
00536           return 0;
00537           break;
00538         }
00539     }                           /* for */
00540 
00541   return -1;
00542 }                               /* nfs_export_tag2path */