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