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 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif 00037 00038 #ifdef _SOLARIS 00039 #include "solaris_port.h" 00040 #define USHRT_MAX 6553 00041 #endif 00042 00043 #include "cidr.h" 00044 #include "ganesha_rpc.h" 00045 #include "log.h" 00046 #include "fsal.h" 00047 #include "nfs23.h" 00048 #include "nfs4.h" 00049 #include "mount.h" 00050 #include "nfs_core.h" 00051 #include "cache_inode.h" 00052 #include "nfs_file_handle.h" 00053 #include "nfs_exports.h" 00054 #include "nfs_tools.h" 00055 #include "nfs_proto_functions.h" 00056 #include "nfs_dupreq.h" 00057 #include "config_parsing.h" 00058 #include "common_utils.h" 00059 #include "nodelist.h" 00060 #include <stdlib.h> 00061 #include <fnmatch.h> 00062 #include <sys/socket.h> 00063 #include <netinet/in.h> 00064 #include <arpa/inet.h> 00065 #include <string.h> 00066 #include <ctype.h> 00067 00068 #define LASTDEFAULT 1048576 00069 00070 #define STRCMP strcasecmp 00071 00072 #define CONF_LABEL_EXPORT "EXPORT" 00073 00074 /* Labels in the export file */ 00075 #define CONF_EXPORT_ID "Export_id" 00076 #define CONF_EXPORT_PATH "Path" 00077 #define CONF_EXPORT_ROOT "Root_Access" 00078 #define CONF_EXPORT_ACCESS "Access" 00079 #define CONF_EXPORT_READ_ACCESS "R_Access" 00080 #define CONF_EXPORT_READWRITE_ACCESS "RW_Access" 00081 #define CONF_EXPORT_MD_ACCESS "MDONLY_Access" 00082 #define CONF_EXPORT_MD_RO_ACCESS "MDONLY_RO_Access" 00083 #define CONF_EXPORT_PSEUDO "Pseudo" 00084 #define CONF_EXPORT_ACCESSTYPE "Access_Type" 00085 #define CONF_EXPORT_ANON_USER "Anonymous_uid" 00086 #define CONF_EXPORT_ANON_ROOT "Anonymous_root_uid" 00087 #define CONF_EXPORT_ALL_ANON "Make_All_Users_Anonymous" 00088 #define CONF_EXPORT_ANON_GROUP "Anonymous_gid" 00089 #define CONF_EXPORT_NFS_PROTO "NFS_Protocols" 00090 #define CONF_EXPORT_TRANS_PROTO "Transport_Protocols" 00091 #define CONF_EXPORT_SECTYPE "SecType" 00092 #define CONF_EXPORT_MAX_READ "MaxRead" 00093 #define CONF_EXPORT_MAX_WRITE "MaxWrite" 00094 #define CONF_EXPORT_PREF_READ "PrefRead" 00095 #define CONF_EXPORT_PREF_WRITE "PrefWrite" 00096 #define CONF_EXPORT_PREF_READDIR "PrefReaddir" 00097 #define CONF_EXPORT_FSID "Filesystem_id" 00098 #define CONF_EXPORT_NOSUID "NOSUID" 00099 #define CONF_EXPORT_NOSGID "NOSGID" 00100 #define CONF_EXPORT_PRIVILEGED_PORT "PrivilegedPort" 00101 #define CONF_EXPORT_USE_DATACACHE "Cache_Data" 00102 #define CONF_EXPORT_FS_SPECIFIC "FS_Specific" 00103 #define CONF_EXPORT_FS_TAG "Tag" 00104 #define CONF_EXPORT_MAX_OFF_WRITE "MaxOffsetWrite" 00105 #define CONF_EXPORT_MAX_OFF_READ "MaxOffsetRead" 00106 #define CONF_EXPORT_MAX_CACHE_SIZE "MaxCacheSize" 00107 #define CONF_EXPORT_REFERRAL "Referral" 00108 #define CONF_EXPORT_PNFS "Use_pNFS" 00109 #define CONF_EXPORT_UQUOTA "User_Quota" 00110 #define CONF_EXPORT_USE_COMMIT "Use_NFS_Commit" 00111 #define CONF_EXPORT_USE_GANESHA_WRITE_BUFFER "Use_Ganesha_Write_Buffer" 00112 #define CONF_EXPORT_USE_FSAL_UP "Use_FSAL_UP" 00113 #define CONF_EXPORT_FSAL_UP_FILTERS "FSAL_UP_Filters" 00114 #define CONF_EXPORT_FSAL_UP_TIMEOUT "FSAL_UP_Timeout" 00115 #define CONF_EXPORT_FSAL_UP_TYPE "FSAL_UP_Type" 00116 #define CONF_EXPORT_USE_COOKIE_VERIFIER "UseCookieVerifier" 00117 00120 /* Internal identifiers */ 00121 #define FLAG_EXPORT_ID 0x000000001 00122 #define FLAG_EXPORT_PATH 0x000000002 00123 00124 #define FLAG_EXPORT_ROOT_OR_ACCESS 0x000000004 00125 00126 #define FLAG_EXPORT_PSEUDO 0x000000010 00127 #define FLAG_EXPORT_ACCESSTYPE 0x000000020 00128 #define FLAG_EXPORT_ANON_ROOT 0x000000040 00129 #define FLAG_EXPORT_NFS_PROTO 0x000000080 00130 #define FLAG_EXPORT_TRANS_PROTO 0x000000100 00131 #define FLAG_EXPORT_SECTYPE 0x000000200 00132 #define FLAG_EXPORT_MAX_READ 0x000000400 00133 #define FLAG_EXPORT_MAX_WRITE 0x000000800 00134 #define FLAG_EXPORT_PREF_READ 0x000001000 00135 #define FLAG_EXPORT_PREF_WRITE 0x000002000 00136 #define FLAG_EXPORT_PREF_READDIR 0x000004000 00137 #define FLAG_EXPORT_FSID 0x000008000 00138 #define FLAG_EXPORT_NOSUID 0x000010000 00139 #define FLAG_EXPORT_NOSGID 0x000020000 00140 #define FLAG_EXPORT_PRIVILEGED_PORT 0x000040000 00141 #define FLAG_EXPORT_USE_DATACACHE 0x000080000 00142 #define FLAG_EXPORT_FS_SPECIFIC 0x000100000 00143 #define FLAG_EXPORT_FS_TAG 0x000200000 00144 #define FLAG_EXPORT_MAX_OFF_WRITE 0x000400000 00145 #define FLAG_EXPORT_MAX_OFF_READ 0x000800000 00146 #define FLAG_EXPORT_MAX_CACHE_SIZE 0x001000000 00147 #define FLAG_EXPORT_USE_PNFS 0x002000000 00148 #define FLAG_EXPORT_ACCESS_LIST 0x004000000 00149 #define FLAG_EXPORT_ACCESSTYPE_LIST 0x008000000 00150 #define FLAG_EXPORT_ANON_GROUP 0x010000000 00151 #define FLAG_EXPORT_ALL_ANON 0x020000000 00152 #define FLAG_EXPORT_ANON_USER 0x040000000 00153 #define FLAG_EXPORT_CACHE_POLICY 0x080000000 00154 #define FLAG_EXPORT_USE_UQUOTA 0x100000000 00155 00156 /* limites for nfs_ParseConfLine */ 00157 /* Used in BuildExportEntry() */ 00158 #define EXPORT_MAX_CLIENTS EXPORTS_NB_MAX_CLIENTS /* number of clients */ 00159 #define EXPORT_MAX_CLIENTLEN 256 /* client name len */ 00160 00175 int nfs_ParseConfLine(char *Argv[], 00176 int nbArgv, 00177 char *line, 00178 int (*separator_function) (char), int (*endLine_func) (char)) 00179 { 00180 int output_value = 0; 00181 int endLine = FALSE; 00182 00183 char *p1 = line; /* Pointeur sur le debut du token */ 00184 char *p2 = NULL; /* Pointeur sur la fin du token */ 00185 00186 /* iteration and checking for array bounds */ 00187 for(; output_value < nbArgv;) 00188 { 00189 00190 if(*p1 == '\0') 00191 return output_value; 00192 00193 /* Je recherche le premier caractere valide */ 00194 for(; *p1 == ' ' || *p1 == '\t'; p1++) ; 00195 00196 /* p1 pointe sur un debut de token, je cherche la fin */ 00197 /* La fin est un blanc, une fin de chaine ou un CR */ 00198 for(p2 = p1; !separator_function(*p2) && !endLine_func(*p2); p2++) ; 00199 00200 /* Possible arret a cet endroit */ 00201 if(endLine_func(*p2)) 00202 endLine = TRUE; 00203 00204 /* je valide la lecture du token */ 00205 *p2 = '\0'; 00206 strcpy(Argv[output_value++], p1); 00207 00208 /* Je me prepare pour la suite */ 00209 if(!endLine) 00210 { 00211 p2 += 1; 00212 p1 = p2; 00213 } 00214 else 00215 return output_value; 00216 00217 } /* for( ; ; ) */ 00218 00219 /* out of bounds */ 00220 if(output_value >= nbArgv) 00221 return -1; 00222 00223 return -2; 00224 00225 } /* nfs_ParseConfLine */ 00226 00248 #if 0 00249 static struct hostent *nfs_LookupHostAddr(char *host) 00250 { 00251 struct hostent *output; 00252 unsigned long hostaddr; 00253 int length = sizeof(hostaddr); 00254 00255 #ifdef _USE_TIRPC_IPV6 00256 struct sockaddr_storage addrv6; 00257 struct sockaddr_in6 *paddrv6 = (struct sockaddr_in6 *)&addrv6; 00258 #endif 00259 00260 hostaddr = inet_addr(host); 00261 /* is it a dotted IP? */ 00262 if (hostaddr == INADDR_NONE) 00263 { 00264 /* Nope. Try to resolve name */ 00265 output = gethostbyname(host); 00266 } 00267 else 00268 { 00269 /* yes, this is an IP, try to get hostent */ 00270 output = gethostbyaddr((char *)&hostaddr, length, AF_INET); 00271 } 00272 00273 #ifdef _USE_TIRPC_IPV6 00274 /* if output == NULL it may be an IPv6 address */ 00275 if(output == NULL) 00276 { 00277 if((output = gethostbyname2(host, AF_INET6)) == NULL) 00278 { 00279 /* Maybe an address in the ASCII format */ 00280 if(inet_pton(AF_INET6, host, paddrv6->sin6_addr.s6_addr)) 00281 { 00282 output = gethostbyaddr(paddrv6->sin6_addr.s6_addr, 00283 sizeof(paddrv6->sin6_addr.s6_addr), AF_INET6); 00284 } 00285 } 00286 } 00287 #endif 00288 00289 return output; 00290 } /* nfs_LookupHostAddr */ 00291 #endif 00292 00317 inline static int string_contains_slash( char* host ) 00318 { 00319 char * c ; 00320 00321 for( c = host ; *c != '\0' ; c++ ) 00322 if( *c == '/' ) 00323 return 1 ; 00324 00325 return 0 ; 00326 } 00327 00328 int nfs_LookupNetworkAddr(char *host, /* [IN] host/address specifier */ 00329 unsigned long *netAddr, /* [OUT] return address */ 00330 unsigned long *netMask) /* [OUT] return address mask */ 00331 { 00332 CIDR * pcidr = NULL ; 00333 00334 if( ( pcidr = cidr_from_str( host ) ) == NULL ) 00335 return 1 ; 00336 00337 memcpy( netAddr, pcidr->addr, sizeof( unsigned long ) ) ; 00338 memcpy( netMask, pcidr->mask, sizeof( unsigned long ) ) ; 00339 00340 /* BE CAREFUL !! The following lines are specific to IPv4. The libcidr support IPv6 as well */ 00341 memset( netAddr, 0, sizeof( unsigned long ) ) ; 00342 memcpy( netAddr, &pcidr->addr[12], 4 ) ; 00343 *netAddr = ntohl( *netAddr ) ; 00344 00345 memset( netMask, 0, sizeof( unsigned long ) ) ; 00346 memcpy( netMask, &pcidr->mask[12], 4 ) ; 00347 *netMask = ntohl( *netMask ) ; 00348 00349 return 0 ; 00350 } /* nfs_LookupNetworkAddr */ 00351 00352 int nfs_AddClientsToClientArray(exportlist_client_t *clients, 00353 int new_clients_number, 00354 char **new_clients_name, int option) 00355 { 00356 int i = 0; 00357 int j = 0; 00358 unsigned int l = 0; 00359 char *client_hostname; 00360 struct addrinfo *info; 00361 exportlist_client_entry_t *p_clients; 00362 int is_wildcarded_host = FALSE; 00363 unsigned long netMask; 00364 unsigned long netAddr; 00365 00366 /* How many clients are there already? */ 00367 j = (*clients).num_clients; 00368 00369 p_clients = (*clients).clientarray; 00370 00371 if(p_clients == NULL) 00372 return ENOMEM; 00373 00374 /* It's now time to set the information related to the new clients */ 00375 for(i = j; i < j + new_clients_number; i++) 00376 { 00377 /* cleans the export entry */ 00378 memset(&p_clients[i], 0, sizeof(exportlist_client_entry_t)); 00379 00380 netMask = 0; /* default value for a host */ 00381 client_hostname = new_clients_name[i - j]; 00382 00383 /* Set client options */ 00384 p_clients[i].options |= option; 00385 00386 /* using netdb to get information about the hostname */ 00387 if(client_hostname[0] == '@') 00388 { 00389 00390 /* Entry is a netgroup definition */ 00391 strncpy(p_clients[i].client.netgroup.netgroupname, 00392 (char *)(client_hostname + 1), MAXHOSTNAMELEN); 00393 00394 p_clients[i].options |= EXPORT_OPTION_NETGRP; 00395 p_clients[i].type = NETGROUP_CLIENT; 00396 00397 LogDebug(COMPONENT_CONFIG, 00398 "----------------- %s to netgroup %s", 00399 (option == EXPORT_OPTION_ROOT ? "Root-access" : "Access"), 00400 p_clients[i].client.netgroup.netgroupname); 00401 } 00402 else if( string_contains_slash( client_hostname ) && 00403 ( nfs_LookupNetworkAddr( (char *)( client_hostname ), 00404 (unsigned long *)&netAddr, 00405 (unsigned long *)&netMask) == 0 ) ) 00406 { 00407 /* Entry is a network definition */ 00408 p_clients[i].client.network.netaddr = netAddr; 00409 p_clients[i].options |= EXPORT_OPTION_NETENT; 00410 p_clients[i].client.network.netmask = netMask; 00411 p_clients[i].type = NETWORK_CLIENT; 00412 00413 LogDebug(COMPONENT_CONFIG, 00414 "----------------- %s to network %s = %d.%d.%d.%d netmask=%x", 00415 (option == EXPORT_OPTION_ROOT ? "Root-access" : "Access"), 00416 client_hostname, 00417 (unsigned int)(p_clients[i].client.network.netaddr >> 24), 00418 (unsigned int)((p_clients[i].client.network.netaddr >> 16) & 0xFF), 00419 (unsigned int)((p_clients[i].client.network.netaddr >> 8) & 0xFF), 00420 (unsigned int)(p_clients[i].client.network.netaddr & 0xFF), 00421 (unsigned int)(p_clients[i].client.network.netmask)); 00422 } 00423 else if( getaddrinfo(client_hostname, NULL, NULL, &info) == 0) 00424 { 00425 /* Entry is a hostif */ 00426 if(info->ai_family == AF_INET) 00427 { 00428 struct in_addr infoaddr = ((struct sockaddr_in *)info->ai_addr)->sin_addr; 00429 memcpy(&(p_clients[i].client.hostif.clientaddr), &infoaddr, 00430 sizeof(struct in_addr)); 00431 p_clients[i].type = HOSTIF_CLIENT; 00432 LogDebug(COMPONENT_CONFIG, 00433 "----------------- %s to client %s = %d.%d.%d.%d", 00434 (option == EXPORT_OPTION_ROOT ? "Root-access" : "Access"), 00435 client_hostname, 00436 (unsigned int)(p_clients[i].client.hostif.clientaddr >> 24), 00437 (unsigned int)((p_clients[i].client.hostif.clientaddr >> 16) & 0xFF), 00438 (unsigned int)((p_clients[i].client.hostif.clientaddr >> 8) & 0xFF), 00439 (unsigned int)(p_clients[i].client.hostif.clientaddr & 0xFF)); 00440 } 00441 else /* AF_INET6 */ 00442 { 00443 struct in6_addr infoaddr = ((struct sockaddr_in6 *)info->ai_addr)->sin6_addr; 00444 /* IPv6 address */ 00445 memcpy(&(p_clients[i].client.hostif.clientaddr6), &infoaddr, 00446 sizeof(struct in6_addr)); 00447 p_clients[i].type = HOSTIF_CLIENT_V6; 00448 } 00449 freeaddrinfo(info); 00450 } 00451 else 00452 { 00453 /* this may be a wildcarded host */ 00454 /* Lookup into the string to see if it contains '*' or '?' */ 00455 is_wildcarded_host = FALSE; 00456 for(l = 0; l < strlen(client_hostname); l++) 00457 { 00458 if((client_hostname[l] == '*') || (client_hostname[l] == '?')) 00459 { 00460 is_wildcarded_host = TRUE; 00461 break; 00462 } 00463 } 00464 00465 if(is_wildcarded_host == TRUE) 00466 { 00467 p_clients[i].type = WILDCARDHOST_CLIENT; 00468 strncpy(p_clients[i].client.wildcard.wildcard, client_hostname, 00469 MAXHOSTNAMELEN); 00470 00471 LogFullDebug(COMPONENT_CONFIG, 00472 "----------------- %s to wildcard %s", 00473 (option == EXPORT_OPTION_ROOT ? "Root-access" : "Access"), 00474 client_hostname); 00475 } 00476 else 00477 { 00478 p_clients[i].type = BAD_CLIENT; 00479 /* Last case: type for client could not be identified. This should not occur */ 00480 LogCrit(COMPONENT_CONFIG, 00481 "Unsupported type for client %s", client_hostname); 00482 } 00483 } 00484 } /* for i */ 00485 00486 /* Before we finish, do not forget to set the new number of clients 00487 * and the new pointer to client array. 00488 */ 00489 (*clients).num_clients += new_clients_number; 00490 00491 return 0; /* success !! */ 00492 } /* nfs_AddClientsToClientArray */ 00493 00494 00504 static int nfs_AddClientsToExportList(exportlist_t * ExportEntry, 00505 int new_clients_number, 00506 char **new_clients_name, int option) 00507 { 00508 /* 00509 * Notifying the export list structure that another option is to be 00510 * handled 00511 */ 00512 ExportEntry->options |= option; 00513 nfs_AddClientsToClientArray( &ExportEntry->clients, new_clients_number, 00514 new_clients_name, option); 00515 return 0; 00516 } /* nfs_AddClientsToExportList */ 00517 00518 #define DEFINED_TWICE_WARNING( _str_ ) \ 00519 LogWarn(COMPONENT_CONFIG, \ 00520 "NFS READ_EXPORT: WARNING: %s defined twice !!! (ignored)", _str_ ) 00521 00522 int parseAccessParam(char *var_name, char *var_value, 00523 exportlist_t *p_entry, int access_option) { 00524 int rc; 00525 char *expended_node_list; 00526 00527 /* temp array of clients */ 00528 char *client_list[EXPORT_MAX_CLIENTS]; 00529 int idx; 00530 int count; 00531 00532 /* expends host[n-m] notations */ 00533 count = 00534 nodelist_common_condensed2extended_nodelist(var_value, &expended_node_list); 00535 00536 if(count <= 0) 00537 { 00538 LogCrit(COMPONENT_CONFIG, 00539 "NFS READ_EXPORT: ERROR: Invalid format for client list in EXPORT::%s definition", 00540 var_name); 00541 00542 return -1; 00543 } 00544 else if(count > EXPORT_MAX_CLIENTS) 00545 { 00546 LogCrit(COMPONENT_CONFIG, 00547 "NFS READ_EXPORT: ERROR: Client list too long (%d>%d)", 00548 count, EXPORT_MAX_CLIENTS); 00549 return -1; 00550 } 00551 00552 /* allocate clients strings */ 00553 for(idx = 0; idx < count; idx++) 00554 { 00555 client_list[idx] = gsh_malloc(EXPORT_MAX_CLIENTLEN); 00556 client_list[idx][0] = '\0'; 00557 } 00558 00559 /* 00560 * Search for coma-separated list of hosts, networks and netgroups 00561 */ 00562 rc = nfs_ParseConfLine(client_list, count, 00563 expended_node_list, find_comma, find_endLine); 00564 00565 /* free the buffer the nodelist module has allocated */ 00566 free(expended_node_list); 00567 00568 if(rc < 0) 00569 { 00570 LogCrit(COMPONENT_CONFIG, 00571 "NFS READ_EXPORT: ERROR: Client list too long (>%d)", count); 00572 00573 /* free client strings */ 00574 for(idx = 0; idx < count; idx++) 00575 gsh_free(client_list[idx]); 00576 00577 return rc; 00578 } 00579 00580 rc = nfs_AddClientsToExportList(p_entry, 00581 rc, (char **)client_list, access_option); 00582 00583 if(rc != 0) 00584 { 00585 LogCrit(COMPONENT_CONFIG, 00586 "NFS READ_EXPORT: ERROR: Invalid client found in \"%s\"", 00587 var_value); 00588 00589 /* free client strings */ 00590 for(idx = 0; idx < count; idx++) 00591 gsh_free(client_list[idx]); 00592 00593 return rc; 00594 } 00595 00596 /* everything is OK */ 00597 00598 /* free client strings */ 00599 for(idx = 0; idx < count; idx++) 00600 gsh_free(client_list[idx]); 00601 00602 return rc; 00603 } 00604 00605 bool_t fsal_specific_checks(exportlist_t *p_entry) 00606 { 00607 #ifdef _USE_GPFS 00608 p_entry->use_fsal_up = TRUE; 00609 00610 if (strncmp(p_entry->fsal_up_type, "DUMB", 4) != 0) 00611 { 00612 LogWarn(COMPONENT_CONFIG, 00613 "NFS READ_EXPORT: ERROR: %s must be \"DUMB\" when using GPFS." 00614 " Setting it to \"DUMB\"", CONF_EXPORT_FSAL_UP_TYPE); 00615 strncpy(p_entry->fsal_up_type,"DUMB", 4); 00616 } 00617 if (p_entry->use_ganesha_write_buffer != FALSE) 00618 { 00619 LogWarn(COMPONENT_CONFIG, 00620 "NFS READ_EXPORT: ERROR: %s must be FALSE when using GPFS. " 00621 "Setting it to FALSE.", CONF_EXPORT_USE_GANESHA_WRITE_BUFFER); 00622 p_entry->use_ganesha_write_buffer = FALSE; 00623 } 00624 #endif 00625 00626 return TRUE; 00627 } 00628 00634 static int BuildExportEntry(config_item_t block, exportlist_t ** pp_export) 00635 { 00636 exportlist_t *p_entry; 00637 int i, rc; 00638 char *var_name; 00639 char *var_value; 00640 00641 /* the mandatory options */ 00642 00643 unsigned int mandatory_options = 00644 (FLAG_EXPORT_ID | FLAG_EXPORT_PATH | 00645 FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_PSEUDO); 00646 00647 /* the given options */ 00648 00649 unsigned int set_options = 0; 00650 00651 int err_flag = FALSE; 00652 00653 /* allocates export entry */ 00654 p_entry = gsh_calloc(1, sizeof(exportlist_t)); 00655 00656 if(p_entry == NULL) 00657 return ENOMEM; 00658 00659 p_entry->status = EXPORTLIST_OK; 00660 p_entry->access_type = ACCESSTYPE_RW; 00661 p_entry->anonymous_uid = (uid_t) ANON_UID; 00662 p_entry->anonymous_gid = (gid_t) ANON_GID; 00663 p_entry->use_commit = TRUE; 00664 p_entry->use_ganesha_write_buffer = FALSE; 00665 p_entry->UseCookieVerifier = TRUE; 00666 00667 /* Defaults for FSAL_UP. It is ok to leave the filter list NULL 00668 * even if we enable the FSAL_UP. */ 00669 #ifdef _USE_FSAL_UP 00670 p_entry->use_fsal_up = FALSE; 00671 p_entry->fsal_up_filter_list = NULL; 00672 p_entry->fsal_up_timeout.seconds = 30; 00673 p_entry->fsal_up_timeout.nseconds = 0; 00674 strncpy(p_entry->fsal_up_type,"DUMB", 4); 00675 /* We don't create the thread until all exports are parsed. */ 00676 memset(&p_entry->fsal_up_thr, 0, sizeof(pthread_t)); 00677 #endif /* _USE_FSAL_UP */ 00678 00679 p_entry->worker_stats = gsh_calloc(nfs_param.core_param.nb_worker, 00680 sizeof(nfs_worker_stat_t)); 00681 00682 /* by default, we support auth_none and auth_sys */ 00683 p_entry->options |= EXPORT_OPTION_AUTH_NONE | EXPORT_OPTION_AUTH_UNIX; 00684 00685 /* by default, we support all NFS versions supported by the core and 00686 both transport protocols */ 00687 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) != 0) 00688 p_entry->options |= EXPORT_OPTION_NFSV2; 00689 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0) 00690 p_entry->options |= EXPORT_OPTION_NFSV3; 00691 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV4) != 0) 00692 p_entry->options |= EXPORT_OPTION_NFSV4; 00693 p_entry->options |= EXPORT_OPTION_UDP | EXPORT_OPTION_TCP; 00694 00695 p_entry->filesystem_id.major = 666; 00696 p_entry->filesystem_id.minor = 666; 00697 00698 p_entry->MaxWrite = 16384; 00699 p_entry->MaxRead = 16384; 00700 p_entry->PrefWrite = 16384; 00701 p_entry->PrefRead = 16384; 00702 p_entry->PrefReaddir = 16384; 00703 00704 init_glist(&p_entry->exp_state_list); 00705 #ifdef _USE_NLM 00706 init_glist(&p_entry->exp_lock_list); 00707 #endif 00708 00709 if(pthread_mutex_init(&p_entry->exp_state_mutex, NULL) == -1) 00710 { 00711 gsh_free(p_entry); 00712 LogCrit(COMPONENT_CONFIG, 00713 "NFS READ_EXPORT: ERROR: could not initialize exp_state_mutex"); 00714 /* free the entry before exiting */ 00715 return -1; 00716 } 00717 00718 strcpy(p_entry->FS_specific, ""); 00719 strcpy(p_entry->FS_tag, ""); 00720 strcpy(p_entry->fullpath, "/"); 00721 strcpy(p_entry->dirname, "/"); 00722 strcpy(p_entry->fsname, ""); 00723 strcpy(p_entry->pseudopath, "/"); 00724 strcpy(p_entry->referral, ""); 00725 00726 /* parse options for this export entry */ 00727 00728 for(i = 0; i < config_GetNbItems(block); i++) 00729 { 00730 config_item_t item; 00731 00732 item = config_GetItemByIndex(block, i); 00733 00734 /* get var name and value */ 00735 rc = config_GetKeyValue(item, &var_name, &var_value); 00736 00737 if((rc != 0) || (var_value == NULL)) 00738 { 00739 gsh_free(p_entry); 00740 LogCrit(COMPONENT_CONFIG, 00741 "NFS READ_EXPORT: ERROR: internal error %d", rc); 00742 /* free the entry before exiting */ 00743 return -1; 00744 } 00745 00746 if(!STRCMP(var_name, CONF_EXPORT_ID)) 00747 { 00748 00749 long int export_id; 00750 char *end_ptr; 00751 00752 /* check if it has not already been set */ 00753 if((set_options & FLAG_EXPORT_ID) == FLAG_EXPORT_ID) 00754 { 00755 DEFINED_TWICE_WARNING(CONF_EXPORT_ID); 00756 continue; 00757 } 00758 00759 /* parse and check export_id */ 00760 errno = 0; 00761 export_id = strtol(var_value, &end_ptr, 10); 00762 00763 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 00764 { 00765 LogCrit(COMPONENT_CONFIG, 00766 "NFS READ_EXPORT: ERROR: Invalid export_id: \"%s\"", 00767 var_value); 00768 err_flag = TRUE; 00769 continue; 00770 } 00771 00772 if(export_id <= 0 || export_id > USHRT_MAX) 00773 { 00774 LogCrit(COMPONENT_CONFIG, 00775 "NFS READ_EXPORT: ERROR: Export_id out of range: \"%ld\"", 00776 export_id); 00777 err_flag = TRUE; 00778 continue; 00779 } 00780 00781 /* set export_id */ 00782 00783 p_entry->id = (unsigned short)export_id; 00784 set_options |= FLAG_EXPORT_ID; 00785 00786 } 00787 else if(!STRCMP(var_name, CONF_EXPORT_PATH)) 00788 { 00789 /* check if it has not already been set */ 00790 if((set_options & FLAG_EXPORT_PATH) == FLAG_EXPORT_PATH) 00791 { 00792 DEFINED_TWICE_WARNING(CONF_EXPORT_PATH); 00793 continue; 00794 } 00795 00796 if(*var_value == '\0') 00797 { 00798 LogCrit(COMPONENT_CONFIG, 00799 "NFS READ_EXPORT: ERROR: Empty export path"); 00800 err_flag = TRUE; 00801 continue; 00802 } 00803 00806 strncpy(p_entry->fullpath, var_value, MAXPATHLEN); 00807 00809 strncpy(p_entry->dirname, var_value, MAXNAMLEN); 00810 strncpy(p_entry->fsname, "", MAXNAMLEN); 00811 00812 set_options |= FLAG_EXPORT_PATH; 00813 00814 } 00815 else if(!STRCMP(var_name, CONF_EXPORT_ROOT)) 00816 { 00817 if(*var_value == '\0') 00818 { 00819 continue; 00820 } 00821 parseAccessParam(var_name, var_value, p_entry, 00822 EXPORT_OPTION_ROOT); 00823 /* Notice that as least one of the three options 00824 * Root_Access, R_Access, or RW_Access has been specified. 00825 */ 00826 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS; 00827 00828 } 00829 else if(!STRCMP(var_name, CONF_EXPORT_ACCESS)) 00830 { 00831 if(*var_value == '\0') 00832 { 00833 continue; 00834 } 00835 parseAccessParam(var_name, var_value, p_entry, 00836 EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS); 00837 /* Notice that as least one of the three options 00838 * Root_Access, R_Access, or RW_Access has been specified. 00839 */ 00840 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_ACCESS_LIST; 00841 } 00842 else if(!STRCMP(var_name, CONF_EXPORT_MD_ACCESS)) 00843 { 00844 if(*var_value == '\0') 00845 { 00846 continue; 00847 } 00848 parseAccessParam(var_name, var_value, p_entry, 00849 EXPORT_OPTION_MD_WRITE_ACCESS | EXPORT_OPTION_MD_READ_ACCESS); 00850 /* Notice that as least one of the three options 00851 * Root_Access, R_Access, or RW_Access has been specified. 00852 */ 00853 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_ACCESSTYPE_LIST; 00854 } 00855 else if(!STRCMP(var_name, CONF_EXPORT_MD_RO_ACCESS)) 00856 { 00857 if(*var_value == '\0') 00858 { 00859 continue; 00860 } 00861 parseAccessParam(var_name, var_value, p_entry, 00862 EXPORT_OPTION_MD_READ_ACCESS); 00863 /* Notice that as least one of the three options 00864 * Root_Access, R_Access, or RW_Access has been specified. 00865 */ 00866 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_ACCESSTYPE_LIST; 00867 } 00868 else if(!STRCMP(var_name, CONF_EXPORT_READ_ACCESS)) 00869 { 00870 if(*var_value == '\0') 00871 { 00872 continue; 00873 } 00874 parseAccessParam(var_name, var_value, p_entry, 00875 EXPORT_OPTION_READ_ACCESS); 00876 /* Notice that as least one of the three options 00877 * Root_Access, R_Access, or RW_Access has been specified. 00878 */ 00879 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_ACCESSTYPE_LIST; 00880 } 00881 else if(!STRCMP(var_name, CONF_EXPORT_READWRITE_ACCESS)) 00882 { 00883 if(*var_value == '\0') 00884 { 00885 continue; 00886 } 00887 parseAccessParam(var_name, var_value, p_entry, 00888 EXPORT_OPTION_READ_ACCESS | EXPORT_OPTION_WRITE_ACCESS); 00889 /* Notice that as least one of the three options 00890 * Root_Access, R_Access, or RW_Access has been specified. 00891 */ 00892 set_options |= FLAG_EXPORT_ROOT_OR_ACCESS | FLAG_EXPORT_ACCESSTYPE_LIST; 00893 } 00894 else if(!STRCMP(var_name, CONF_EXPORT_PSEUDO)) 00895 { 00896 00897 /* check if it has not already been set */ 00898 if((set_options & FLAG_EXPORT_PSEUDO) == FLAG_EXPORT_PSEUDO) 00899 { 00900 DEFINED_TWICE_WARNING(CONF_EXPORT_PSEUDO); 00901 continue; 00902 } 00903 00904 if(*var_value != '/') 00905 { 00906 LogCrit(COMPONENT_CONFIG, 00907 "NFS READ_EXPORT: ERROR: Pseudo path must begin with a slash (invalid pseudo path: %s).", 00908 var_value); 00909 err_flag = TRUE; 00910 continue; 00911 } 00912 00913 strncpy(p_entry->pseudopath, var_value, MAXPATHLEN); 00914 00915 set_options |= FLAG_EXPORT_PSEUDO; 00916 p_entry->options |= EXPORT_OPTION_PSEUDO; 00917 00918 } 00919 else if(!STRCMP(var_name, CONF_EXPORT_REFERRAL)) 00920 { 00921 strncpy(p_entry->referral, var_value, MAXPATHLEN); 00922 } 00923 else if(!STRCMP(var_name, CONF_EXPORT_ACCESSTYPE)) 00924 { 00925 // check if it has not already been set 00926 if((set_options & FLAG_EXPORT_ACCESSTYPE) == FLAG_EXPORT_ACCESSTYPE) 00927 { 00928 DEFINED_TWICE_WARNING(CONF_EXPORT_ACCESSTYPE); 00929 continue; 00930 } 00931 00932 if(!STRCMP(var_value, "RW")) 00933 { 00934 p_entry->access_type = ACCESSTYPE_RW; 00935 } 00936 else if(!STRCMP(var_value, "RO")) 00937 { 00938 p_entry->access_type = ACCESSTYPE_RO; 00939 } 00940 else if(!STRCMP(var_value, "MDONLY")) 00941 { 00942 p_entry->access_type = ACCESSTYPE_MDONLY; 00943 } 00944 else if(!STRCMP(var_value, "MDONLY_RO")) 00945 { 00946 p_entry->access_type = ACCESSTYPE_MDONLY_RO; 00947 } 00948 else 00949 { 00950 LogCrit(COMPONENT_CONFIG, 00951 "NFS READ_EXPORT: ERROR: Invalid access type \"%s\". Values can be: RW, RO, MDONLY, MDONLY_RO.", 00952 var_value); 00953 err_flag = TRUE; 00954 continue; 00955 } 00956 00957 set_options |= FLAG_EXPORT_ACCESSTYPE; 00958 00959 } 00960 else if(!STRCMP(var_name, CONF_EXPORT_NFS_PROTO)) 00961 { 00962 00963 # define MAX_NFSPROTO 10 /* large enough !!! */ 00964 # define MAX_NFSPROTO_LEN 256 /* so is it !!! */ 00965 00966 char *nfsvers_list[MAX_NFSPROTO]; 00967 int idx, count; 00968 00969 /* check if it has not already been set */ 00970 if((set_options & FLAG_EXPORT_NFS_PROTO) == FLAG_EXPORT_NFS_PROTO) 00971 { 00972 DEFINED_TWICE_WARNING(CONF_EXPORT_NFS_PROTO); 00973 continue; 00974 } 00975 00976 /* reset nfs proto flags (clean defaults) */ 00977 p_entry->options &= ~(EXPORT_OPTION_NFSV2 00978 | EXPORT_OPTION_NFSV3 | EXPORT_OPTION_NFSV4); 00979 00980 /* allocate nfs vers strings */ 00981 for(idx = 0; idx < MAX_NFSPROTO; idx++) 00982 nfsvers_list[idx] = gsh_malloc(MAX_NFSPROTO_LEN); 00983 00984 /* 00985 * Search for coma-separated list of nfsprotos 00986 */ 00987 count = nfs_ParseConfLine(nfsvers_list, MAX_NFSPROTO, 00988 var_value, find_comma, find_endLine); 00989 00990 if(count < 0) 00991 { 00992 err_flag = TRUE; 00993 LogCrit(COMPONENT_CONFIG, 00994 "NFS READ_EXPORT: ERROR: NFS protocols list too long (>%d)", 00995 MAX_NFSPROTO); 00996 00997 /* free sec strings */ 00998 for(idx = 0; idx < MAX_NFSPROTO; idx++) 00999 gsh_free(nfsvers_list[idx]); 01000 01001 continue; 01002 } 01003 01004 /* add each Nfs protocol flag to the option field. */ 01005 01006 for(idx = 0; idx < count; idx++) 01007 { 01008 if(!STRCMP(nfsvers_list[idx], "2")) 01009 { 01010 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) != 0) 01011 p_entry->options |= EXPORT_OPTION_NFSV2; 01012 else 01013 { 01014 LogInfo(COMPONENT_CONFIG, 01015 "NFS READ_EXPORT:NFS version 2 is disabled in NFS_Core_Param."); 01016 } 01017 } 01018 else if(!STRCMP(nfsvers_list[idx], "3")) 01019 { 01020 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0) 01021 p_entry->options |= EXPORT_OPTION_NFSV3; 01022 else 01023 { 01024 LogInfo(COMPONENT_CONFIG, 01025 "NFS READ_EXPORT:NFS version 3 is disabled in NFS_Core_Param."); 01026 } 01027 } 01028 else if(!STRCMP(nfsvers_list[idx], "4")) 01029 { 01030 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV4) != 0) 01031 p_entry->options |= EXPORT_OPTION_NFSV4; 01032 else 01033 { 01034 LogInfo(COMPONENT_CONFIG, 01035 "NFS READ_EXPORT:NFS version 4 is disabled in NFS_Core_Param."); 01036 } 01037 } 01038 else 01039 { 01040 LogCrit(COMPONENT_CONFIG, 01041 "NFS READ_EXPORT: ERROR: Invalid NFS version \"%s\". Values can be: 2, 3, 4.", 01042 nfsvers_list[idx]); 01043 err_flag = TRUE; 01044 } 01045 } 01046 01047 /* free sec strings */ 01048 for(idx = 0; idx < MAX_NFSPROTO; idx++) 01049 gsh_free(nfsvers_list[idx]); 01050 01051 /* check that at least one nfs protocol has been specified */ 01052 if((p_entry->options & (EXPORT_OPTION_NFSV2 01053 | EXPORT_OPTION_NFSV3 | EXPORT_OPTION_NFSV4)) == 0) 01054 { 01055 LogCrit(COMPONENT_CONFIG, 01056 "NFS READ_EXPORT: WARNING: /!\\ Empty NFS_protocols list"); 01057 err_flag = TRUE; 01058 } 01059 01060 set_options |= FLAG_EXPORT_NFS_PROTO; 01061 01062 } 01063 else if(!STRCMP(var_name, CONF_EXPORT_TRANS_PROTO)) 01064 { 01065 01066 # define MAX_TRANSPROTO 10 /* large enough !!! */ 01067 # define MAX_TRANSPROTO_LEN 256 /* so is it !!! */ 01068 01069 char *transproto_list[MAX_TRANSPROTO]; 01070 int idx, count; 01071 01072 /* check if it has not already been set */ 01073 if((set_options & FLAG_EXPORT_TRANS_PROTO) == FLAG_EXPORT_TRANS_PROTO) 01074 { 01075 DEFINED_TWICE_WARNING(CONF_EXPORT_TRANS_PROTO); 01076 continue; 01077 } 01078 01079 /* reset TRANS proto flags (clean defaults) */ 01080 p_entry->options &= ~(EXPORT_OPTION_UDP | EXPORT_OPTION_TCP); 01081 01082 /* allocate TRANS vers strings */ 01083 for(idx = 0; idx < MAX_TRANSPROTO; idx++) 01084 transproto_list[idx] = gsh_malloc(MAX_TRANSPROTO_LEN); 01085 01086 /* 01087 * Search for coma-separated list of TRANSprotos 01088 */ 01089 count = nfs_ParseConfLine(transproto_list, MAX_TRANSPROTO, 01090 var_value, find_comma, find_endLine); 01091 01092 if(count < 0) 01093 { 01094 err_flag = TRUE; 01095 LogCrit(COMPONENT_CONFIG, 01096 "NFS READ_EXPORT: ERROR: Protocol list too long (>%d)", 01097 MAX_TRANSPROTO); 01098 01099 /* free sec strings */ 01100 for(idx = 0; idx < MAX_TRANSPROTO; idx++) 01101 gsh_free(transproto_list[idx]); 01102 01103 continue; 01104 } 01105 01106 /* add each TRANS protocol flag to the option field. */ 01107 01108 for(idx = 0; idx < count; idx++) 01109 { 01110 if(!STRCMP(transproto_list[idx], "UDP")) 01111 { 01112 p_entry->options |= EXPORT_OPTION_UDP; 01113 } 01114 else if(!STRCMP(transproto_list[idx], "TCP")) 01115 { 01116 p_entry->options |= EXPORT_OPTION_TCP; 01117 } 01118 else 01119 { 01120 LogCrit(COMPONENT_CONFIG, 01121 "NFS READ_EXPORT: ERROR: Invalid protocol \"%s\". Values can be: UDP, TCP.", 01122 transproto_list[idx]); 01123 err_flag = TRUE; 01124 } 01125 } 01126 01127 /* free sec strings */ 01128 for(idx = 0; idx < MAX_TRANSPROTO; idx++) 01129 gsh_free(transproto_list[idx]); 01130 01131 /* check that at least one TRANS protocol has been specified */ 01132 if((p_entry->options & (EXPORT_OPTION_UDP | EXPORT_OPTION_TCP)) == 0) 01133 LogCrit(COMPONENT_CONFIG, 01134 "TRANS READ_EXPORT: WARNING: /!\\ Empty protocol list"); 01135 01136 set_options |= FLAG_EXPORT_TRANS_PROTO; 01137 01138 } 01139 else if(!STRCMP(var_name, CONF_EXPORT_ALL_ANON)) 01140 { 01141 /* check if it has not already been set */ 01142 if((set_options & FLAG_EXPORT_ALL_ANON) == FLAG_EXPORT_ALL_ANON) 01143 { 01144 DEFINED_TWICE_WARNING(CONF_EXPORT_ALL_ANON); 01145 continue; 01146 } 01147 01148 if (StrToBoolean(var_value)) 01149 p_entry->all_anonymous = TRUE; 01150 01151 set_options |= FLAG_EXPORT_ANON_USER; 01152 } 01153 else if(!STRCMP(var_name, CONF_EXPORT_ANON_ROOT)) 01154 { 01155 long int anon_uid; 01156 char *end_ptr; 01157 01158 /* check if it has not already been set */ 01159 if((set_options & FLAG_EXPORT_ANON_ROOT) == FLAG_EXPORT_ANON_ROOT) 01160 { 01161 DEFINED_TWICE_WARNING(CONF_EXPORT_ANON_USER); 01162 continue; 01163 } 01164 01165 if((set_options & FLAG_EXPORT_ANON_USER) == FLAG_EXPORT_ANON_USER) 01166 { 01167 DEFINED_TWICE_WARNING(CONF_EXPORT_ANON_ROOT); 01168 continue; 01169 } 01170 01171 /* parse and check anon_uid */ 01172 errno = 0; 01173 01174 anon_uid = strtol(var_value, &end_ptr, 10); 01175 01176 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01177 { 01178 LogCrit(COMPONENT_CONFIG, 01179 "NFS READ_EXPORT: ERROR: Invalid Anonymous_uid: \"%s\"", 01180 var_value); 01181 err_flag = TRUE; 01182 continue; 01183 } 01184 01185 /* set anon_uid */ 01186 p_entry->anonymous_uid = (uid_t) anon_uid; 01187 01188 set_options |= FLAG_EXPORT_ANON_ROOT; 01189 01190 } 01191 else if(!STRCMP(var_name, CONF_EXPORT_ANON_USER)) 01192 { 01193 long int anon_uid; 01194 char *end_ptr; 01195 01196 /* check if it has not already been set */ 01197 if((set_options & FLAG_EXPORT_ANON_USER) == FLAG_EXPORT_ANON_USER) 01198 { 01199 DEFINED_TWICE_WARNING(CONF_EXPORT_ANON_USER); 01200 continue; 01201 } 01202 01203 if((set_options & FLAG_EXPORT_ANON_ROOT) == FLAG_EXPORT_ANON_ROOT) 01204 { 01205 DEFINED_TWICE_WARNING(CONF_EXPORT_ANON_ROOT); 01206 continue; 01207 } 01208 01209 /* parse and check anon_uid */ 01210 errno = 0; 01211 01212 anon_uid = strtol(var_value, &end_ptr, 10); 01213 01214 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01215 { 01216 LogCrit(COMPONENT_CONFIG, 01217 "NFS READ_EXPORT: ERROR: Invalid Anonymous_uid: \"%s\"", 01218 var_value); 01219 err_flag = TRUE; 01220 continue; 01221 } 01222 01223 /* set anon_uid */ 01224 01225 p_entry->anonymous_uid = (uid_t) anon_uid; 01226 01227 set_options |= FLAG_EXPORT_ANON_USER; 01228 01229 } 01230 else if(!STRCMP(var_name, CONF_EXPORT_ANON_GROUP)) 01231 { 01232 01233 long int anon_gid; 01234 char *end_ptr; 01235 01236 /* check if it has not already been set */ 01237 if((set_options & FLAG_EXPORT_ANON_GROUP) == FLAG_EXPORT_ANON_GROUP) 01238 { 01239 DEFINED_TWICE_WARNING(CONF_EXPORT_ANON_GROUP); 01240 continue; 01241 } 01242 01243 /* parse and check anon_uid */ 01244 errno = 0; 01245 01246 anon_gid = strtol(var_value, &end_ptr, 10); 01247 01248 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01249 { 01250 LogCrit(COMPONENT_CONFIG, 01251 "NFS READ_EXPORT: ERROR: Invalid Anonymous_gid: \"%s\"", 01252 var_value); 01253 err_flag = TRUE; 01254 continue; 01255 } 01256 01257 /* set anon_uid */ 01258 01259 p_entry->anonymous_gid = (gid_t) anon_gid; 01260 01261 set_options |= FLAG_EXPORT_ANON_GROUP; 01262 01263 } 01264 else if(!STRCMP(var_name, CONF_EXPORT_SECTYPE)) 01265 { 01266 # define MAX_SECTYPE 10 /* large enough !!! */ 01267 # define MAX_SECTYPE_LEN 256 /* so is it !!! */ 01268 01269 char *sec_list[MAX_SECTYPE]; 01270 int idx, count; 01271 01272 /* check if it has not already been set */ 01273 if((set_options & FLAG_EXPORT_SECTYPE) == FLAG_EXPORT_SECTYPE) 01274 { 01275 DEFINED_TWICE_WARNING(CONF_EXPORT_SECTYPE); 01276 continue; 01277 } 01278 01279 /* reset security flags (clean defaults) */ 01280 p_entry->options &= ~(EXPORT_OPTION_AUTH_NONE 01281 | EXPORT_OPTION_AUTH_UNIX 01282 | EXPORT_OPTION_RPCSEC_GSS_NONE 01283 | EXPORT_OPTION_RPCSEC_GSS_INTG 01284 | EXPORT_OPTION_RPCSEC_GSS_PRIV); 01285 01286 /* allocate sec strings */ 01287 for(idx = 0; idx < MAX_SECTYPE; idx++) 01288 sec_list[idx] = gsh_malloc(MAX_SECTYPE_LEN); 01289 01290 /* 01291 * Search for coma-separated list of sectypes 01292 */ 01293 count = nfs_ParseConfLine(sec_list, MAX_SECTYPE, 01294 var_value, find_comma, find_endLine); 01295 01296 if(count < 0) 01297 { 01298 err_flag = TRUE; 01299 LogCrit(COMPONENT_CONFIG, 01300 "NFS READ_EXPORT: ERROR: SecType list too long (>%d)", 01301 MAX_SECTYPE); 01302 01303 /* free sec strings */ 01304 for(idx = 0; idx < MAX_SECTYPE; idx++) 01305 gsh_free(sec_list[idx]); 01306 01307 continue; 01308 } 01309 01310 /* add each sectype flag to the option field. */ 01311 01312 for(idx = 0; idx < count; idx++) 01313 { 01314 if(!STRCMP(sec_list[idx], "none")) 01315 { 01316 p_entry->options |= EXPORT_OPTION_AUTH_NONE; 01317 } 01318 else if(!STRCMP(sec_list[idx], "sys")) 01319 { 01320 p_entry->options |= EXPORT_OPTION_AUTH_UNIX; 01321 } 01322 else if(!STRCMP(sec_list[idx], "krb5")) 01323 { 01324 p_entry->options |= EXPORT_OPTION_RPCSEC_GSS_NONE; 01325 } 01326 else if(!STRCMP(sec_list[idx], "krb5i")) 01327 { 01328 p_entry->options |= EXPORT_OPTION_RPCSEC_GSS_INTG; 01329 } 01330 else if(!STRCMP(sec_list[idx], "krb5p")) 01331 { 01332 p_entry->options |= EXPORT_OPTION_RPCSEC_GSS_PRIV; 01333 } 01334 else 01335 { 01336 LogCrit(COMPONENT_CONFIG, 01337 "NFS READ_EXPORT: ERROR: Invalid SecType \"%s\". Values can be: none, sys, krb5, krb5i, krb5p.", 01338 sec_list[idx]); 01339 err_flag = TRUE; 01340 } 01341 } 01342 01343 /* free sec strings */ 01344 for(idx = 0; idx < MAX_SECTYPE; idx++) 01345 gsh_free(sec_list[idx]); 01346 01347 /* check that at least one sectype has been specified */ 01348 if((p_entry->options & (EXPORT_OPTION_AUTH_NONE 01349 | EXPORT_OPTION_AUTH_UNIX 01350 | EXPORT_OPTION_RPCSEC_GSS_NONE 01351 | EXPORT_OPTION_RPCSEC_GSS_INTG 01352 | EXPORT_OPTION_RPCSEC_GSS_PRIV)) == 0) 01353 LogCrit(COMPONENT_CONFIG, 01354 "NFS READ_EXPORT: WARNING: /!\\ Empty SecType"); 01355 01356 set_options |= FLAG_EXPORT_SECTYPE; 01357 01358 } 01359 else if(!STRCMP(var_name, CONF_EXPORT_MAX_READ)) 01360 { 01361 long long int size; 01362 char *end_ptr; 01363 01364 /* check if it has not already been set */ 01365 if((set_options & FLAG_EXPORT_MAX_READ) == FLAG_EXPORT_MAX_READ) 01366 { 01367 DEFINED_TWICE_WARNING(CONF_EXPORT_MAX_READ); 01368 continue; 01369 } 01370 01371 errno = 0; 01372 size = strtoll(var_value, &end_ptr, 10); 01373 01374 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01375 { 01376 LogCrit(COMPONENT_CONFIG, 01377 "NFS READ_EXPORT: ERROR: Invalid MaxRead: \"%s\"", 01378 var_value); 01379 err_flag = TRUE; 01380 continue; 01381 } 01382 01383 if(size < 0) 01384 { 01385 LogCrit(COMPONENT_CONFIG, 01386 "NFS READ_EXPORT: ERROR: MaxRead out of range: %lld", 01387 size); 01388 err_flag = TRUE; 01389 continue; 01390 } 01391 01392 /* set filesystem_id */ 01393 01394 p_entry->MaxRead = (fsal_size_t) size; 01395 p_entry->options |= EXPORT_OPTION_MAXREAD; 01396 01397 set_options |= FLAG_EXPORT_MAX_READ; 01398 } 01399 else if(!STRCMP(var_name, CONF_EXPORT_MAX_WRITE)) 01400 { 01401 long long int size; 01402 char *end_ptr; 01403 01404 /* check if it has not already been set */ 01405 if((set_options & FLAG_EXPORT_MAX_WRITE) == FLAG_EXPORT_MAX_WRITE) 01406 { 01407 DEFINED_TWICE_WARNING(CONF_EXPORT_MAX_WRITE); 01408 continue; 01409 } 01410 01411 errno = 0; 01412 size = strtoll(var_value, &end_ptr, 10); 01413 01414 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01415 { 01416 LogCrit(COMPONENT_CONFIG, 01417 "NFS READ_EXPORT: ERROR: Invalid MaxWrite: \"%s\"", 01418 var_value); 01419 err_flag = TRUE; 01420 continue; 01421 } 01422 01423 if(size < 0) 01424 { 01425 LogCrit(COMPONENT_CONFIG, 01426 "NFS READ_EXPORT: ERROR: MaxWrite out of range: %lld", 01427 size); 01428 err_flag = TRUE; 01429 continue; 01430 } 01431 01432 /* set filesystem_id */ 01433 01434 p_entry->MaxWrite = (fsal_size_t) size; 01435 p_entry->options |= EXPORT_OPTION_MAXWRITE; 01436 01437 set_options |= FLAG_EXPORT_MAX_WRITE; 01438 } 01439 else if(!STRCMP(var_name, CONF_EXPORT_PREF_READ)) 01440 { 01441 long long int size; 01442 char *end_ptr; 01443 01444 /* check if it has not already been set */ 01445 if((set_options & FLAG_EXPORT_PREF_READ) == FLAG_EXPORT_PREF_READ) 01446 { 01447 DEFINED_TWICE_WARNING(CONF_EXPORT_PREF_READ); 01448 continue; 01449 } 01450 01451 errno = 0; 01452 size = strtoll(var_value, &end_ptr, 10); 01453 01454 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01455 { 01456 LogCrit(COMPONENT_CONFIG, 01457 "NFS READ_EXPORT: ERROR: Invalid PrefRead: \"%s\"", 01458 var_value); 01459 err_flag = TRUE; 01460 continue; 01461 } 01462 01463 if(size < 0) 01464 { 01465 LogCrit(COMPONENT_CONFIG, 01466 "NFS READ_EXPORT: ERROR: PrefRead out of range: %lld", 01467 size); 01468 err_flag = TRUE; 01469 continue; 01470 } 01471 01472 /* set filesystem_id */ 01473 01474 p_entry->PrefRead = (fsal_size_t) size; 01475 p_entry->options |= EXPORT_OPTION_PREFREAD; 01476 01477 set_options |= FLAG_EXPORT_PREF_READ; 01478 } 01479 else if(!STRCMP(var_name, CONF_EXPORT_PREF_WRITE)) 01480 { 01481 long long int size; 01482 char *end_ptr; 01483 01484 /* check if it has not already been set */ 01485 if((set_options & FLAG_EXPORT_PREF_WRITE) == FLAG_EXPORT_PREF_WRITE) 01486 { 01487 DEFINED_TWICE_WARNING(CONF_EXPORT_PREF_WRITE); 01488 continue; 01489 } 01490 01491 errno = 0; 01492 size = strtoll(var_value, &end_ptr, 10); 01493 01494 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01495 { 01496 LogCrit(COMPONENT_CONFIG, 01497 "NFS READ_EXPORT: ERROR: Invalid PrefWrite: \"%s\"", 01498 var_value); 01499 err_flag = TRUE; 01500 continue; 01501 } 01502 01503 if(size < 0) 01504 { 01505 LogCrit(COMPONENT_CONFIG, 01506 "NFS READ_EXPORT: ERROR: PrefWrite out of range: %lld", 01507 size); 01508 err_flag = TRUE; 01509 continue; 01510 } 01511 01512 /* set filesystem_id */ 01513 01514 p_entry->PrefWrite = (fsal_size_t) size; 01515 p_entry->options |= EXPORT_OPTION_PREFWRITE; 01516 01517 set_options |= FLAG_EXPORT_PREF_WRITE; 01518 } 01519 else if(!STRCMP(var_name, CONF_EXPORT_PREF_READDIR)) 01520 { 01521 long long int size; 01522 char *end_ptr; 01523 01524 /* check if it has not already been set */ 01525 if((set_options & FLAG_EXPORT_PREF_READDIR) == FLAG_EXPORT_PREF_READDIR) 01526 { 01527 DEFINED_TWICE_WARNING(CONF_EXPORT_PREF_READDIR); 01528 continue; 01529 } 01530 01531 errno = 0; 01532 size = strtoll(var_value, &end_ptr, 10); 01533 01534 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01535 { 01536 LogCrit(COMPONENT_CONFIG, 01537 "NFS READ_EXPORT: ERROR: Invalid PrefReaddir: \"%s\"", 01538 var_value); 01539 err_flag = TRUE; 01540 continue; 01541 } 01542 01543 if(size < 0) 01544 { 01545 LogCrit(COMPONENT_CONFIG, 01546 "NFS READ_EXPORT: ERROR: PrefReaddir out of range: %lld", 01547 size); 01548 err_flag = TRUE; 01549 continue; 01550 } 01551 01552 /* set filesystem_id */ 01553 01554 p_entry->PrefReaddir = (fsal_size_t) size; 01555 p_entry->options |= EXPORT_OPTION_PREFRDDIR; 01556 01557 set_options |= FLAG_EXPORT_PREF_READDIR; 01558 } 01559 else if(!STRCMP(var_name, CONF_EXPORT_PREF_WRITE)) 01560 { 01561 long long int size; 01562 char *end_ptr; 01563 01564 /* check if it has not already been set */ 01565 if((set_options & FLAG_EXPORT_PREF_WRITE) == FLAG_EXPORT_PREF_WRITE) 01566 { 01567 DEFINED_TWICE_WARNING(CONF_EXPORT_PREF_WRITE); 01568 continue; 01569 } 01570 01571 errno = 0; 01572 size = strtoll(var_value, &end_ptr, 10); 01573 01574 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01575 { 01576 LogCrit(COMPONENT_CONFIG, 01577 "NFS READ_EXPORT: ERROR: Invalid PrefWrite: \"%s\"", 01578 var_value); 01579 err_flag = TRUE; 01580 continue; 01581 } 01582 01583 if(size < 0) 01584 { 01585 LogCrit(COMPONENT_CONFIG, 01586 "NFS READ_EXPORT: ERROR: PrefWrite out of range: %lld", 01587 size); 01588 err_flag = TRUE; 01589 continue; 01590 } 01591 01592 /* set filesystem_id */ 01593 01594 p_entry->PrefWrite = (fsal_size_t) size; 01595 p_entry->options |= EXPORT_OPTION_PREFWRITE; 01596 01597 set_options |= FLAG_EXPORT_PREF_WRITE; 01598 01599 } 01600 else if(!STRCMP(var_name, CONF_EXPORT_FSID)) 01601 { 01602 long long int major, minor; 01603 char *end_ptr; 01604 01605 /* check if it has not already been set */ 01606 if((set_options & FLAG_EXPORT_FSID) == FLAG_EXPORT_FSID) 01607 { 01608 DEFINED_TWICE_WARNING(CONF_EXPORT_FSID); 01609 continue; 01610 } 01611 01612 /* parse and check filesystem id */ 01613 errno = 0; 01614 major = strtoll(var_value, &end_ptr, 10); 01615 01616 if(end_ptr == NULL || *end_ptr != '.' || errno != 0) 01617 { 01618 LogCrit(COMPONENT_CONFIG, 01619 "NFS READ_EXPORT: ERROR: Invalid filesystem_id: \"%s\"", 01620 var_value); 01621 err_flag = TRUE; 01622 continue; 01623 } 01624 01625 end_ptr++; /* the first character after the dot */ 01626 01627 errno = 0; 01628 minor = strtoll(end_ptr, &end_ptr, 10); 01629 01630 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01631 { 01632 LogCrit(COMPONENT_CONFIG, 01633 "NFS READ_EXPORT: ERROR: Invalid filesystem_id: \"%s\"", 01634 var_value); 01635 err_flag = TRUE; 01636 continue; 01637 } 01638 01639 if(major < 0 || minor < 0) 01640 { 01641 LogCrit(COMPONENT_CONFIG, 01642 "NFS READ_EXPORT: ERROR: filesystem_id out of range: %lld.%lld", 01643 major, minor); 01644 err_flag = TRUE; 01645 continue; 01646 } 01647 01648 /* set filesystem_id */ 01649 01650 p_entry->filesystem_id.major = (fsal_u64_t) major; 01651 p_entry->filesystem_id.minor = (fsal_u64_t) minor; 01652 01653 set_options |= FLAG_EXPORT_FSID; 01654 01655 } 01656 else if(!STRCMP(var_name, CONF_EXPORT_NOSUID)) 01657 { 01658 /* check if it has not already been set */ 01659 if((set_options & FLAG_EXPORT_NOSUID) == FLAG_EXPORT_NOSUID) 01660 { 01661 DEFINED_TWICE_WARNING(CONF_EXPORT_NOSUID); 01662 continue; 01663 } 01664 01665 switch (StrToBoolean(var_value)) 01666 { 01667 case 1: 01668 p_entry->options |= EXPORT_OPTION_NOSUID; 01669 break; 01670 01671 case 0: 01672 /*default (false) */ 01673 break; 01674 01675 default: /* error */ 01676 { 01677 LogCrit(COMPONENT_CONFIG, 01678 "NFS READ_EXPORT: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 01679 var_name, var_value); 01680 err_flag = TRUE; 01681 continue; 01682 } 01683 } 01684 01685 set_options |= FLAG_EXPORT_NOSUID; 01686 01687 } 01688 else if(!STRCMP(var_name, CONF_EXPORT_NOSGID)) 01689 { 01690 /* check if it has not already been set */ 01691 if((set_options & FLAG_EXPORT_NOSGID) == FLAG_EXPORT_NOSGID) 01692 { 01693 DEFINED_TWICE_WARNING(CONF_EXPORT_NOSGID); 01694 continue; 01695 } 01696 01697 switch (StrToBoolean(var_value)) 01698 { 01699 case 1: 01700 p_entry->options |= EXPORT_OPTION_NOSGID; 01701 break; 01702 01703 case 0: 01704 /*default (false) */ 01705 break; 01706 01707 default: /* error */ 01708 LogCrit(COMPONENT_CONFIG, 01709 "NFS READ_EXPORT: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 01710 var_name, var_value); 01711 err_flag = TRUE; 01712 continue; 01713 } 01714 01715 set_options |= FLAG_EXPORT_NOSGID; 01716 } 01717 else if(!STRCMP(var_name, CONF_EXPORT_PRIVILEGED_PORT)) 01718 { 01719 /* check if it has not already been set */ 01720 if((set_options & FLAG_EXPORT_PRIVILEGED_PORT) == FLAG_EXPORT_PRIVILEGED_PORT) 01721 { 01722 DEFINED_TWICE_WARNING("FLAG_EXPORT_PRIVILEGED_PORT"); 01723 continue; 01724 } 01725 01726 switch (StrToBoolean(var_value)) 01727 { 01728 case 1: 01729 p_entry->options |= EXPORT_OPTION_PRIVILEGED_PORT; 01730 break; 01731 01732 case 0: 01733 /*default (false) */ 01734 break; 01735 01736 default: /* error */ 01737 LogCrit(COMPONENT_CONFIG, 01738 "NFS READ_EXPORT: ERROR: Invalid value for '%s' (%s): TRUE or FALSE expected.", 01739 var_name, var_value); 01740 err_flag = TRUE; 01741 continue; 01742 } 01743 set_options |= FLAG_EXPORT_PRIVILEGED_PORT; 01744 } 01745 else if(!STRCMP(var_name, CONF_EXPORT_USE_DATACACHE)) 01746 { 01747 /* check if it has not already been set */ 01748 if((set_options & FLAG_EXPORT_USE_DATACACHE) == FLAG_EXPORT_USE_DATACACHE) 01749 { 01750 DEFINED_TWICE_WARNING("FLAG_EXPORT_USE_DATACACHE"); 01751 continue; 01752 } 01753 01754 switch (StrToBoolean(var_value)) 01755 { 01756 case 1: 01757 p_entry->options |= EXPORT_OPTION_USE_DATACACHE; 01758 break; 01759 01760 case 0: 01761 /*default (false) */ 01762 break; 01763 01764 default: /* error */ 01765 LogCrit(COMPONENT_CONFIG, 01766 "NFS READ_EXPORT: ERROR: Invalid value for '%s' (%s): TRUE or FALSE expected.", 01767 var_name, var_value); 01768 err_flag = TRUE; 01769 continue; 01770 } 01771 set_options |= FLAG_EXPORT_USE_DATACACHE; 01772 } 01773 else if(!STRCMP(var_name, CONF_EXPORT_PNFS)) 01774 { 01775 /* check if it has not already been set */ 01776 if((set_options & FLAG_EXPORT_USE_PNFS) == FLAG_EXPORT_USE_PNFS) 01777 { 01778 DEFINED_TWICE_WARNING("FLAG_EXPORT_USE_PNFS"); 01779 continue; 01780 } 01781 01782 switch (StrToBoolean(var_value)) 01783 { 01784 case 1: 01785 p_entry->options |= EXPORT_OPTION_USE_PNFS; 01786 break; 01787 01788 case 0: 01789 /*default (false) */ 01790 break; 01791 01792 default: /* error */ 01793 LogCrit(COMPONENT_CONFIG, 01794 "NFS READ_EXPORT: ERROR: Invalid value for '%s' (%s): TRUE or FALSE expected.", 01795 var_name, var_value); 01796 err_flag = TRUE; 01797 continue; 01798 } 01799 set_options |= EXPORT_OPTION_USE_PNFS; 01800 } 01801 else if(!STRCMP(var_name, CONF_EXPORT_UQUOTA ) ) 01802 { 01803 /* check if it has not already been set */ 01804 if((set_options & FLAG_EXPORT_USE_UQUOTA) == FLAG_EXPORT_USE_UQUOTA) 01805 { 01806 DEFINED_TWICE_WARNING("FLAG_EXPORT_USE_UQUOTA"); 01807 continue; 01808 } 01809 01810 switch (StrToBoolean(var_value)) 01811 { 01812 case 1: 01813 p_entry->options |= EXPORT_OPTION_USE_UQUOTA; 01814 break; 01815 01816 case 0: 01817 /*default (false) */ 01818 break; 01819 01820 default: /* error */ 01821 LogCrit(COMPONENT_CONFIG, 01822 "NFS READ_EXPORT: ERROR: Invalid value for '%s' (%s): TRUE or FALSE expected.", 01823 var_name, var_value); 01824 err_flag = TRUE; 01825 continue; 01826 } 01827 set_options |= EXPORT_OPTION_USE_UQUOTA; 01828 01829 } 01830 else if(!STRCMP(var_name, CONF_EXPORT_FS_SPECIFIC)) 01831 { 01832 /* check if it has not already been set */ 01833 if((set_options & FLAG_EXPORT_FS_SPECIFIC) == FLAG_EXPORT_FS_SPECIFIC) 01834 { 01835 DEFINED_TWICE_WARNING(CONF_EXPORT_FS_SPECIFIC); 01836 continue; 01837 } 01838 01839 strncpy(p_entry->FS_specific, var_value, MAXPATHLEN); 01840 01841 set_options |= FLAG_EXPORT_FS_SPECIFIC; 01842 01843 } 01844 else if(!STRCMP(var_name, CONF_EXPORT_FS_TAG)) 01845 { 01846 /* check if it has not already been set */ 01847 if((set_options & FLAG_EXPORT_FS_TAG) == FLAG_EXPORT_FS_TAG) 01848 { 01849 DEFINED_TWICE_WARNING(CONF_EXPORT_FS_TAG); 01850 continue; 01851 } 01852 01853 strncpy(p_entry->FS_tag, var_value, MAXPATHLEN); 01854 01855 set_options |= FLAG_EXPORT_FS_TAG; 01856 01857 } 01858 else if(!STRCMP(var_name, CONF_EXPORT_MAX_OFF_WRITE)) 01859 { 01860 long long int offset; 01861 char *end_ptr; 01862 01863 errno = 0; 01864 offset = strtoll(var_value, &end_ptr, 10); 01865 01866 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01867 { 01868 LogCrit(COMPONENT_CONFIG, 01869 "NFS READ_EXPORT: ERROR: Invalid MaxOffsetWrite: \"%s\"", 01870 var_value); 01871 err_flag = TRUE; 01872 continue; 01873 } 01874 01875 /* set filesystem_id */ 01876 01877 p_entry->MaxOffsetWrite = (fsal_size_t) offset; 01878 p_entry->options |= EXPORT_OPTION_MAXOFFSETWRITE; 01879 01880 set_options |= FLAG_EXPORT_MAX_OFF_WRITE; 01881 01882 } 01883 else if(!STRCMP(var_name, CONF_EXPORT_MAX_CACHE_SIZE)) 01884 { 01885 long long int offset; 01886 char *end_ptr; 01887 01888 errno = 0; 01889 offset = strtoll(var_value, &end_ptr, 10); 01890 01891 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01892 { 01893 LogCrit(COMPONENT_CONFIG, 01894 "NFS READ_EXPORT: ERROR: Invalid MaxCacheSize: \"%s\"", 01895 var_value); 01896 err_flag = TRUE; 01897 continue; 01898 } 01899 01900 /* set filesystem_id */ 01901 01902 p_entry->MaxCacheSize = (fsal_size_t) offset; 01903 p_entry->options |= EXPORT_OPTION_MAXCACHESIZE; 01904 01905 set_options |= FLAG_EXPORT_MAX_CACHE_SIZE; 01906 01907 } 01908 else if(!STRCMP(var_name, CONF_EXPORT_MAX_OFF_READ)) 01909 { 01910 long long int offset; 01911 char *end_ptr; 01912 01913 errno = 0; 01914 offset = strtoll(var_value, &end_ptr, 10); 01915 01916 if(end_ptr == NULL || *end_ptr != '\0' || errno != 0) 01917 { 01918 LogCrit(COMPONENT_CONFIG, 01919 "NFS READ_EXPORT: ERROR: Invalid MaxOffsetRead: \"%s\"", 01920 var_value); 01921 err_flag = TRUE; 01922 continue; 01923 } 01924 01925 /* set filesystem_id */ 01926 01927 p_entry->MaxOffsetRead = (fsal_size_t) offset; 01928 p_entry->options |= EXPORT_OPTION_MAXOFFSETREAD; 01929 01930 set_options |= FLAG_EXPORT_MAX_OFF_READ; 01931 01932 } 01933 else if(!STRCMP(var_name, CONF_EXPORT_USE_COMMIT)) 01934 { 01935 switch (StrToBoolean(var_value)) 01936 { 01937 case 1: 01938 p_entry->use_commit = TRUE; 01939 break; 01940 01941 case 0: 01942 p_entry->use_commit = FALSE; 01943 break; 01944 01945 default: /* error */ 01946 { 01947 LogCrit(COMPONENT_CONFIG, 01948 "NFS READ_EXPORT: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 01949 var_name, var_value); 01950 err_flag = TRUE; 01951 continue; 01952 } 01953 } 01954 } 01955 else if(!STRCMP(var_name, CONF_EXPORT_USE_GANESHA_WRITE_BUFFER)) 01956 { 01957 switch (StrToBoolean(var_value)) 01958 { 01959 case 1: 01960 p_entry->use_ganesha_write_buffer = TRUE; 01961 break; 01962 01963 case 0: 01964 p_entry->use_ganesha_write_buffer = FALSE; 01965 break; 01966 01967 default: /* error */ 01968 { 01969 LogCrit(COMPONENT_CONFIG, 01970 "NFS READ_EXPORT: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 01971 var_name, var_value); 01972 err_flag = TRUE; 01973 continue; 01974 } 01975 } 01976 } 01977 #ifdef _USE_FSAL_UP 01978 else if(!STRCMP(var_name, CONF_EXPORT_FSAL_UP_TYPE)) 01979 { 01980 strncpy(p_entry->fsal_up_type,var_value,sizeof(var_value)); 01981 } 01982 else if(!STRCMP(var_name, CONF_EXPORT_FSAL_UP_TIMEOUT)) 01983 { 01984 /* Right now we are expecting seconds ... we should support 01985 * nseconds as well! */ 01986 p_entry->fsal_up_timeout.seconds = atoi(var_value); 01987 if (p_entry->fsal_up_timeout.seconds < 0 01988 || p_entry->fsal_up_timeout.nseconds < 0) 01989 { 01990 p_entry->fsal_up_timeout.seconds = 0; 01991 p_entry->fsal_up_timeout.nseconds = 0; 01992 } 01993 } 01994 else if(!STRCMP(var_name, CONF_EXPORT_FSAL_UP_FILTERS)) 01995 { 01996 /* TODO: Parse the strings and form a list. 01997 * Later each name will match a predefined filter 01998 * in the FSAL UP interface. */ 01999 p_entry->fsal_up_filter_list = NULL; 02000 } 02001 else if(!STRCMP(var_name, CONF_EXPORT_USE_FSAL_UP)) 02002 { 02003 switch (StrToBoolean(var_value)) 02004 { 02005 case 1: 02006 p_entry->use_fsal_up = TRUE; 02007 break; 02008 case 0: 02009 p_entry->use_fsal_up = FALSE; 02010 break; 02011 default: /* error */ 02012 { 02013 LogCrit(COMPONENT_CONFIG, 02014 "USR_FSAL_UP: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 02015 var_name, var_value); 02016 err_flag = TRUE; 02017 continue; 02018 } 02019 } 02020 } 02021 #endif /* _USE_FSAL_UP */ 02022 else if(!STRCMP(var_name, CONF_EXPORT_USE_COOKIE_VERIFIER)) 02023 { 02024 switch (StrToBoolean(var_value)) 02025 { 02026 case 1: 02027 p_entry->UseCookieVerifier = TRUE; 02028 break; 02029 02030 case 0: 02031 p_entry->UseCookieVerifier = FALSE; 02032 break; 02033 02034 default: /* error */ 02035 { 02036 LogCrit(COMPONENT_CONFIG, 02037 "NFS READ_EXPORT: ERROR: Invalid value for %s (%s): TRUE or FALSE expected.", 02038 var_name, var_value); 02039 err_flag = TRUE; 02040 continue; 02041 } 02042 } 02043 } 02044 else 02045 { 02046 LogCrit(COMPONENT_CONFIG, 02047 "NFS READ_EXPORT: WARNING: Unknown option: %s", 02048 var_name); 02049 } 02050 02051 } 02052 02054 if((set_options & mandatory_options) != mandatory_options) 02055 { 02056 if((set_options & FLAG_EXPORT_ID) != FLAG_EXPORT_ID) 02057 LogCrit(COMPONENT_CONFIG, 02058 "NFS READ_EXPORT: ERROR: Missing mandatory parameter %s", 02059 CONF_EXPORT_ID ); 02060 02061 if((set_options & FLAG_EXPORT_PATH) != FLAG_EXPORT_PATH) 02062 LogCrit(COMPONENT_CONFIG, 02063 "NFS READ_EXPORT: ERROR: Missing mandatory parameter %s", 02064 CONF_EXPORT_PATH); 02065 02066 if((set_options & FLAG_EXPORT_ROOT_OR_ACCESS) != FLAG_EXPORT_ROOT_OR_ACCESS) 02067 LogCrit(COMPONENT_CONFIG, 02068 "NFS READ_EXPORT: ERROR: Missing mandatory parameter %s or %s or %s", 02069 CONF_EXPORT_ROOT, CONF_EXPORT_READ_ACCESS, 02070 CONF_EXPORT_READWRITE_ACCESS); 02071 02072 if((set_options & FLAG_EXPORT_PSEUDO) != FLAG_EXPORT_PSEUDO) 02073 LogCrit(COMPONENT_CONFIG, 02074 "NFS READ_EXPORT: ERROR: Missing mandatory parameter %s", 02075 CONF_EXPORT_PSEUDO); 02076 02077 err_flag = TRUE; 02078 } 02079 02080 if ( 02081 ((set_options & FLAG_EXPORT_ACCESSTYPE) || (set_options & FLAG_EXPORT_ACCESS_LIST)) && 02082 (set_options & FLAG_EXPORT_ACCESSTYPE_LIST)) 02083 { 02084 LogCrit(COMPONENT_CONFIG, 02085 "NFS READ_EXPORT: ERROR: %s list cannot be used when %s and/or %s are used in the same export entry config.", 02086 CONF_EXPORT_READWRITE_ACCESS, CONF_EXPORT_ACCESSTYPE, 02087 CONF_EXPORT_ACCESS); 02088 err_flag = TRUE; 02089 } 02090 02091 if ((set_options & FLAG_EXPORT_ACCESSTYPE) || (set_options & FLAG_EXPORT_ACCESS_LIST)) 02092 p_entry->new_access_list_version = FALSE; 02093 else 02094 p_entry->new_access_list_version = TRUE; 02095 02096 /* check if there had any error. 02097 * if so, free the p_entry and return an error. 02098 */ 02099 if(err_flag) 02100 { 02101 gsh_free(p_entry); 02102 return -1; 02103 } 02104 02105 /* Here we can make sure certain options are turned on for specific FSALs */ 02106 if (!fsal_specific_checks(p_entry)) 02107 { 02108 LogCrit(COMPONENT_CONFIG, 02109 "NFS READ_EXPORT: ERROR: Found conflicts in export entry."); 02110 return -1; 02111 } 02112 02113 *pp_export = p_entry; 02114 02115 LogEvent(COMPONENT_CONFIG, 02116 "NFS READ_EXPORT: Export %d (%s) successfully parsed", 02117 p_entry->id, p_entry->fullpath); 02118 02119 return 0; 02120 02121 } 02122 02128 static char *client_root_access[] = { "*" }; 02129 02130 exportlist_t *BuildDefaultExport() 02131 { 02132 exportlist_t *p_entry; 02133 int rc; 02134 02135 /* allocates new export entry */ 02136 p_entry = gsh_malloc(sizeof(exportlist_t)); 02137 02138 if(p_entry == NULL) 02139 return NULL; 02140 02143 p_entry->next = NULL; 02144 p_entry->options = 0; 02145 p_entry->status = EXPORTLIST_OK; 02146 p_entry->clients.num_clients = 0; 02147 p_entry->access_type = ACCESSTYPE_RW; 02148 p_entry->anonymous_uid = (uid_t) ANON_UID; 02149 p_entry->MaxOffsetWrite = (fsal_off_t) 0; 02150 p_entry->MaxOffsetRead = (fsal_off_t) 0; 02151 p_entry->MaxCacheSize = (fsal_off_t) 0; 02152 02153 /* by default, we support auth_none and auth_sys */ 02154 p_entry->options |= EXPORT_OPTION_AUTH_NONE | EXPORT_OPTION_AUTH_UNIX; 02155 02156 /* by default, we support all NFS versions supported by the core and both transport protocols */ 02157 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV2) != 0) 02158 p_entry->options |= EXPORT_OPTION_NFSV2; 02159 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV3) != 0) 02160 p_entry->options |= EXPORT_OPTION_NFSV3; 02161 if((nfs_param.core_param.core_options & CORE_OPTION_NFSV4) != 0) 02162 p_entry->options |= EXPORT_OPTION_NFSV4; 02163 p_entry->options |= EXPORT_OPTION_UDP | EXPORT_OPTION_TCP; 02164 02165 p_entry->filesystem_id.major = (fsal_u64_t) 101; 02166 p_entry->filesystem_id.minor = (fsal_u64_t) 101; 02167 02168 p_entry->MaxWrite = (fsal_size_t) 16384; 02169 p_entry->MaxRead = (fsal_size_t) 16384; 02170 p_entry->PrefWrite = (fsal_size_t) 16384; 02171 p_entry->PrefRead = (fsal_size_t) 16384; 02172 p_entry->PrefReaddir = (fsal_size_t) 16384; 02173 02174 strcpy(p_entry->FS_specific, ""); 02175 strcpy(p_entry->FS_tag, "ganesha"); 02176 02177 p_entry->id = 1; 02178 02179 strcpy(p_entry->fullpath, "/"); 02180 strcpy(p_entry->dirname, "/"); 02181 strcpy(p_entry->fsname, ""); 02182 strcpy(p_entry->pseudopath, "/"); 02183 strcpy(p_entry->referral, ""); 02184 02185 p_entry->UseCookieVerifier = TRUE; 02186 02190 rc = nfs_AddClientsToExportList(p_entry, 1, client_root_access, EXPORT_OPTION_ROOT); 02191 02192 if(rc != 0) 02193 { 02194 LogCrit(COMPONENT_CONFIG, 02195 "NFS READ_EXPORT: ERROR: Invalid client \"%s\"", 02196 (char *)client_root_access); 02197 return NULL; 02198 } 02199 02200 LogEvent(COMPONENT_CONFIG, 02201 "NFS READ_EXPORT: Export %d (%s) successfully parsed", 02202 p_entry->id, p_entry->fullpath); 02203 02204 return p_entry; 02205 02206 } /* BuildDefaultExport */ 02207 02214 int ReadExports(config_file_t in_config, /* The file that contains the export list */ 02215 exportlist_t ** ppexportlist) /* Pointer to the export list */ 02216 { 02217 02218 int nb_blk, rc, i; 02219 char *blk_name; 02220 int err_flag = FALSE; 02221 02222 exportlist_t *p_export_item = NULL; 02223 exportlist_t *p_export_last = NULL; 02224 02225 int nb_entries = 0; 02226 02227 if(!ppexportlist) 02228 return -EFAULT; 02229 02230 *ppexportlist = NULL; 02231 02232 /* get the number of blocks in the configuration file */ 02233 nb_blk = config_GetNbBlocks(in_config); 02234 02235 if(nb_blk < 0) 02236 return -1; 02237 02238 /* Iteration on config file blocks. */ 02239 for(i = 0; i < nb_blk; i++) 02240 { 02241 config_item_t block; 02242 02243 block = config_GetBlockByIndex(in_config, i); 02244 02245 if(block == NULL) 02246 return -1; 02247 02248 /* get the name of the block */ 02249 blk_name = config_GetBlockName(block); 02250 02251 if(blk_name == NULL) 02252 return -1; 02253 02254 if(!STRCMP(blk_name, CONF_LABEL_EXPORT)) 02255 { 02256 02257 rc = BuildExportEntry(block, &p_export_item); 02258 02259 /* If the entry is errorneous, ignore it 02260 * and continue checking syntax of other entries. 02261 */ 02262 if(rc != 0) 02263 { 02264 err_flag = TRUE; 02265 continue; 02266 } 02267 02268 p_export_item->next = NULL; 02269 02270 if(*ppexportlist == NULL) 02271 { 02272 *ppexportlist = p_export_item; 02273 } 02274 else 02275 { 02276 p_export_last->next = p_export_item; 02277 } 02278 p_export_last = p_export_item; 02279 02280 nb_entries++; 02281 02282 } 02283 02284 } 02285 02286 if(err_flag) 02287 { 02288 return -1; 02289 } 02290 else 02291 return nb_entries; 02292 } 02293 02297 int export_client_match(sockaddr_t *hostaddr, 02298 char *ipstring, 02299 exportlist_client_t *clients, 02300 exportlist_client_entry_t * pclient_found, 02301 unsigned int export_option) 02302 { 02303 unsigned int i; 02304 int rc; 02305 char hostname[MAXHOSTNAMELEN]; 02306 in_addr_t addr = get_in_addr(hostaddr); 02307 02308 if(export_option & EXPORT_OPTION_ROOT) 02309 LogFullDebug(COMPONENT_DISPATCH, 02310 "Looking for root access entries"); 02311 02312 if(export_option & EXPORT_OPTION_READ_ACCESS) 02313 LogFullDebug(COMPONENT_DISPATCH, 02314 "Looking for nonroot access read entries"); 02315 02316 if(export_option & EXPORT_OPTION_WRITE_ACCESS) 02317 LogFullDebug(COMPONENT_DISPATCH, 02318 "Looking for nonroot access write entries"); 02319 02320 for(i = 0; i < clients->num_clients; i++) 02321 { 02322 /* Make sure the client entry has the permission flags we're looking for 02323 * Also make sure we aren't looking at a root client entry when we're not root. */ 02324 if(((clients->clientarray[i].options & export_option) == 0) || 02325 ((clients->clientarray[i].options & EXPORT_OPTION_ROOT) != (export_option & EXPORT_OPTION_ROOT))) 02326 continue; 02327 02328 switch (clients->clientarray[i].type) 02329 { 02330 case HOSTIF_CLIENT: 02331 if(clients->clientarray[i].client.hostif.clientaddr == addr) 02332 { 02333 LogFullDebug(COMPONENT_DISPATCH, "This matches host address"); 02334 *pclient_found = clients->clientarray[i]; 02335 return TRUE; 02336 } 02337 break; 02338 02339 case NETWORK_CLIENT: 02340 LogDebug( COMPONENT_DISPATCH, "test NETWORK_CLIENT: addr=%#.08X, netmask=%#.08X, match with %#.08X", 02341 clients->clientarray[i].client.network.netaddr, 02342 clients->clientarray[i].client.network.netmask, ntohl(addr)); 02343 LogFullDebug(COMPONENT_DISPATCH, 02344 "Test net %d.%d.%d.%d in %d.%d.%d.%d ??", 02345 (unsigned int)(clients->clientarray[i].client.network.netaddr >> 24), 02346 (unsigned int)((clients->clientarray[i].client.network.netaddr >> 16) & 0xFF), 02347 (unsigned int)((clients->clientarray[i].client.network.netaddr >> 8) & 0xFF), 02348 (unsigned int)(clients->clientarray[i].client.network.netaddr & 0xFF), 02349 (unsigned int)(addr >> 24), 02350 (unsigned int)(addr >> 16) & 0xFF, 02351 (unsigned int)(addr >> 8) & 0xFF, 02352 (unsigned int)(addr & 0xFF)); 02353 02354 if((clients->clientarray[i].client.network.netmask & ntohl(addr)) == 02355 clients->clientarray[i].client.network.netaddr) 02356 { 02357 LogFullDebug(COMPONENT_DISPATCH, "This matches network address"); 02358 *pclient_found = clients->clientarray[i]; 02359 return TRUE; 02360 } 02361 break; 02362 02363 case NETGROUP_CLIENT: 02364 /* Try to get the entry from th IP/name cache */ 02365 if((rc = nfs_ip_name_get(hostaddr, hostname)) != IP_NAME_SUCCESS) 02366 { 02367 if(rc == IP_NAME_NOT_FOUND) 02368 { 02369 /* IPaddr was not cached, add it to the cache */ 02370 if(nfs_ip_name_add(hostaddr, hostname) != IP_NAME_SUCCESS) 02371 { 02372 /* Major failure, name could not be resolved */ 02373 break; 02374 } 02375 } 02376 } 02377 02378 /* At this point 'hostname' should contain the name that was found */ 02379 if(innetgr 02380 (clients->clientarray[i].client.netgroup.netgroupname, hostname, 02381 NULL, NULL) == 1) 02382 { 02383 *pclient_found = clients->clientarray[i]; 02384 return TRUE; 02385 } 02386 break; 02387 02388 case WILDCARDHOST_CLIENT: 02389 /* Now checking for IP wildcards */ 02390 if(fnmatch 02391 (clients->clientarray[i].client.wildcard.wildcard, ipstring, 02392 FNM_PATHNAME) == 0) 02393 { 02394 *pclient_found = clients->clientarray[i]; 02395 return TRUE; 02396 } 02397 02398 LogFullDebug(COMPONENT_DISPATCH, 02399 "Did not match the ip address with a wildcard."); 02400 02401 /* Try to get the entry from th IP/name cache */ 02402 if((rc = nfs_ip_name_get(hostaddr, hostname)) != IP_NAME_SUCCESS) 02403 { 02404 if(rc == IP_NAME_NOT_FOUND) 02405 { 02406 /* IPaddr was not cached, add it to the cache */ 02407 if(nfs_ip_name_add(hostaddr, hostname) != IP_NAME_SUCCESS) 02408 { 02409 /* Major failure, name could not be resolved */ 02410 LogFullDebug(COMPONENT_DISPATCH, 02411 "Could not resolve hostame for addr %u.%u.%u.%u ... not checking if a hostname wildcard matches", 02412 (unsigned int)(addr & 0xFF), 02413 (unsigned int)(addr >> 8) & 0xFF, 02414 (unsigned int)(addr >> 16) & 0xFF, 02415 (unsigned int)(addr >> 24)); 02416 break; 02417 } 02418 } 02419 } 02420 LogFullDebug(COMPONENT_DISPATCH, 02421 "Wildcarded hostname: testing if '%s' matches '%s'", 02422 hostname, clients->clientarray[i].client.wildcard.wildcard); 02423 02424 /* At this point 'hostname' should contain the name that was found */ 02425 if(fnmatch 02426 (clients->clientarray[i].client.wildcard.wildcard, hostname, 02427 FNM_PATHNAME) == 0) 02428 { 02429 *pclient_found = clients->clientarray[i]; 02430 return TRUE; 02431 } 02432 LogFullDebug(COMPONENT_DISPATCH, "'%s' not matching '%s'", 02433 hostname, clients->clientarray[i].client.wildcard.wildcard); 02434 break; 02435 02436 case GSSPRINCIPAL_CLIENT: 02438 LogFullDebug(COMPONENT_DISPATCH, 02439 "----------> Unsupported type GSS_PRINCIPAL_CLIENT"); 02440 return FALSE; 02441 break; 02442 02443 case BAD_CLIENT: 02444 LogDebug(COMPONENT_DISPATCH, 02445 "Bad client in position %u seen in export list", i ); 02446 continue ; 02447 02448 default: 02449 LogCrit(COMPONENT_DISPATCH, 02450 "Unsupported client in position %u in export list with type %u", i, clients->clientarray[i].type); 02451 continue ; 02452 } /* switch */ 02453 } /* for */ 02454 02455 /* no export found for this option */ 02456 return FALSE; 02457 02458 } /* export_client_match */ 02459 02460 int export_client_matchv6(struct in6_addr *paddrv6, 02461 exportlist_client_t *clients, 02462 exportlist_client_entry_t * pclient_found, 02463 unsigned int export_option) 02464 { 02465 unsigned int i; 02466 02467 if(export_option & EXPORT_OPTION_ROOT) 02468 LogFullDebug(COMPONENT_DISPATCH, 02469 "Looking for root access entries"); 02470 02471 if(export_option & EXPORT_OPTION_READ_ACCESS) 02472 LogFullDebug(COMPONENT_DISPATCH, 02473 "Looking for nonroot access read entries"); 02474 02475 if(export_option & EXPORT_OPTION_WRITE_ACCESS) 02476 LogFullDebug(COMPONENT_DISPATCH, 02477 "Looking for nonroot access write entries"); 02478 02479 for(i = 0; i < clients->num_clients; i++) 02480 { 02481 /* Make sure the client entry has the permission flags we're looking for 02482 * Also make sure we aren't looking at a root client entry when we're not root. */ 02483 if(((clients->clientarray[i].options & export_option) == 0) || 02484 ((clients->clientarray[i].options & EXPORT_OPTION_ROOT) != (export_option & EXPORT_OPTION_ROOT))) 02485 continue; 02486 02487 switch (clients->clientarray[i].type) 02488 { 02489 case HOSTIF_CLIENT: 02490 case NETWORK_CLIENT: 02491 case NETGROUP_CLIENT: 02492 case WILDCARDHOST_CLIENT: 02493 case GSSPRINCIPAL_CLIENT: 02494 break; 02495 02496 case HOSTIF_CLIENT_V6: 02497 if(!memcmp(clients->clientarray[i].client.hostif.clientaddr6.s6_addr, paddrv6->s6_addr, 16)) /* Remember that IPv6 address are 128 bits = 16 bytes long */ 02498 { 02499 LogFullDebug(COMPONENT_DISPATCH, 02500 "This matches host adress in IPv6"); 02501 *pclient_found = clients->clientarray[i]; 02502 return TRUE; 02503 } 02504 break; 02505 02506 default: 02507 return FALSE; /* Should never occurs */ 02508 break; 02509 } /* switch */ 02510 } /* for */ 02511 02512 /* no export found for this option */ 02513 return FALSE; 02514 } /* export_client_matchv6 */ 02515 02528 int nfs_export_check_security(struct svc_req *req, exportlist_t * pexport) 02529 { 02530 switch (req->rq_cred.oa_flavor) 02531 { 02532 case AUTH_NONE: 02533 if((pexport->options & EXPORT_OPTION_AUTH_NONE) == 0) 02534 { 02535 LogInfo(COMPONENT_DISPATCH, 02536 "Export %s does not support AUTH_NONE", 02537 pexport->dirname); 02538 return FALSE; 02539 } 02540 break; 02541 02542 case AUTH_UNIX: 02543 if((pexport->options & EXPORT_OPTION_AUTH_UNIX) == 0) 02544 { 02545 LogInfo(COMPONENT_DISPATCH, 02546 "Export %s does not support AUTH_UNIX", 02547 pexport->dirname); 02548 return FALSE; 02549 } 02550 break; 02551 02552 #ifdef _HAVE_GSSAPI 02553 case RPCSEC_GSS: 02554 if((pexport->options & 02555 (EXPORT_OPTION_RPCSEC_GSS_NONE | 02556 EXPORT_OPTION_RPCSEC_GSS_INTG | 02557 EXPORT_OPTION_RPCSEC_GSS_PRIV)) == 0) 02558 { 02559 LogInfo(COMPONENT_DISPATCH, 02560 "Export %s does not support RPCSEC_GSS", 02561 pexport->dirname); 02562 return FALSE; 02563 } 02564 else 02565 { 02566 struct svc_rpc_gss_data *gd; 02567 rpc_gss_svc_t svc; 02568 gd = SVCAUTH_PRIVATE(req->rq_xprt->xp_auth); 02569 svc = gd->sec.svc; 02570 LogFullDebug(COMPONENT_DISPATCH, 02571 "Testing svc %d", (int) svc); 02572 switch(svc) 02573 { 02574 case RPCSEC_GSS_SVC_NONE: 02575 if((pexport->options & 02576 EXPORT_OPTION_RPCSEC_GSS_NONE) == 0) 02577 { 02578 LogInfo(COMPONENT_DISPATCH, 02579 "Export %s does not support " 02580 "RPCSEC_GSS_SVC_NONE", 02581 pexport->dirname); 02582 return FALSE; 02583 } 02584 break; 02585 02586 case RPCSEC_GSS_SVC_INTEGRITY: 02587 if((pexport->options & 02588 EXPORT_OPTION_RPCSEC_GSS_INTG) == 0) 02589 { 02590 LogInfo(COMPONENT_DISPATCH, 02591 "Export %s does not support " 02592 "RPCSEC_GSS_SVC_INTEGRITY", 02593 pexport->dirname); 02594 return FALSE; 02595 } 02596 break; 02597 02598 case RPCSEC_GSS_SVC_PRIVACY: 02599 if((pexport->options & 02600 EXPORT_OPTION_RPCSEC_GSS_PRIV) == 0) 02601 { 02602 LogInfo(COMPONENT_DISPATCH, 02603 "Export %s does not support " 02604 "RPCSEC_GSS_SVC_PRIVACY", 02605 pexport->dirname); 02606 return FALSE; 02607 } 02608 break; 02609 02610 default: 02611 LogInfo(COMPONENT_DISPATCH, 02612 "Export %s does not support unknown " 02613 "RPCSEC_GSS_SVC %d", 02614 pexport->dirname, (int) svc); 02615 return FALSE; 02616 } 02617 } 02618 break; 02619 #endif 02620 default: 02621 LogInfo(COMPONENT_DISPATCH, 02622 "Export %s does not support unknown oa_flavor %d", 02623 pexport->dirname, (int) req->rq_cred.oa_flavor); 02624 return FALSE; 02625 } 02626 02627 return TRUE; 02628 } 02629 02650 int nfs_export_check_access(sockaddr_t *hostaddr, 02651 struct svc_req *ptr_req, 02652 exportlist_t * pexport, 02653 unsigned int nfs_prog, 02654 unsigned int mnt_prog, 02655 hash_table_t * ht_ip_stats, 02656 pool_t *ip_stats_pool, 02657 exportlist_client_entry_t * pclient_found, 02658 struct user_cred *user_credentials, 02659 bool_t proc_makes_write) 02660 { 02661 int rc; 02662 char ipstring[SOCK_NAME_MAX]; 02663 int ipvalid; 02664 02665 if (pexport != NULL) 02666 { 02667 if(proc_makes_write && (pexport->access_type == ACCESSTYPE_RO)) 02668 return EXPORT_WRITE_ATTEMPT_WHEN_RO; 02669 else if(proc_makes_write && (pexport->access_type == ACCESSTYPE_MDONLY_RO)) 02670 return EXPORT_WRITE_ATTEMPT_WHEN_MDONLY_RO; 02671 } 02672 02673 ipstring[0] = '\0'; 02674 ipvalid = sprint_sockip(hostaddr, ipstring, sizeof(ipstring)); 02675 LogFullDebug(COMPONENT_DISPATCH, 02676 "nfs_export_check_access for address %s", ipstring); 02677 02678 /* For now, no matching client is found */ 02679 memset(pclient_found, 0, sizeof(exportlist_client_entry_t)); 02680 02681 /* PROC NULL is always authorized, in all protocols */ 02682 if(ptr_req->rq_proc == 0) 02683 { 02684 LogFullDebug(COMPONENT_DISPATCH, 02685 "Granted NULL proc"); 02686 return EXPORT_PERMISSION_GRANTED; 02687 } 02688 02689 #ifdef _USE_TIPRC_IPV6 02690 if(hostaddr->ss_family == AF_INET) 02691 #endif 02692 /* Increment the stats per client address (for IPv4 Only) */ 02693 if((rc = 02694 nfs_ip_stats_incr(ht_ip_stats, hostaddr, nfs_prog, mnt_prog, 02695 ptr_req)) == IP_STATS_NOT_FOUND) 02696 { 02697 if(nfs_ip_stats_add(ht_ip_stats, hostaddr, ip_stats_pool) == 02698 IP_STATS_SUCCESS) 02699 rc = nfs_ip_stats_incr(ht_ip_stats, hostaddr, nfs_prog, 02700 mnt_prog, ptr_req); 02701 } 02702 02703 #ifdef _USE_TIRPC_IPV6 02704 if(hostaddr->ss_family == AF_INET) 02705 { 02706 #endif /* _USE_TIRPC_IPV6 */ 02707 02708 /* Use IP address as a string for wild character access checks. */ 02709 if(!ipvalid) 02710 { 02711 LogCrit(COMPONENT_DISPATCH, 02712 "Could not convert the IPv4 address to a character string."); 02713 return EXPORT_PERMISSION_DENIED; 02714 } 02715 02716 if(pexport == NULL) 02717 { 02718 LogCrit(COMPONENT_DISPATCH, 02719 "Error: no export to verify permissions against."); 02720 return EXPORT_PERMISSION_DENIED; 02721 } 02722 02723 /* check if any root access export matches this client */ 02724 if(user_credentials->caller_uid == 0) 02725 { 02726 if(export_client_match(hostaddr, 02727 ipstring, 02728 &(pexport->clients), 02729 pclient_found, 02730 EXPORT_OPTION_ROOT)) 02731 { 02732 if(pexport->access_type == ACCESSTYPE_MDONLY_RO || 02733 pexport->access_type == ACCESSTYPE_MDONLY) 02734 { 02735 LogFullDebug(COMPONENT_DISPATCH, 02736 "Root granted MDONLY export permission"); 02737 return EXPORT_MDONLY_GRANTED; 02738 } 02739 else 02740 { 02741 LogFullDebug(COMPONENT_DISPATCH, 02742 "Root granted export permission"); 02743 return EXPORT_PERMISSION_GRANTED; 02744 } 02745 } 02746 } 02747 /* else, check if any access only export matches this client */ 02748 if(proc_makes_write) 02749 { 02750 if(export_client_match(hostaddr, 02751 ipstring, 02752 &(pexport->clients), 02753 pclient_found, 02754 EXPORT_OPTION_WRITE_ACCESS)) 02755 { 02756 LogFullDebug(COMPONENT_DISPATCH, 02757 "Write permission to export granted"); 02758 return EXPORT_PERMISSION_GRANTED; 02759 } 02760 else if(pexport->new_access_list_version && 02761 export_client_match(hostaddr, 02762 ipstring, 02763 &(pexport->clients), 02764 pclient_found, 02765 EXPORT_OPTION_MD_WRITE_ACCESS)) 02766 { 02767 pexport->access_type = ACCESSTYPE_MDONLY; 02768 LogFullDebug(COMPONENT_DISPATCH, 02769 "MDONLY export permission granted"); 02770 return EXPORT_MDONLY_GRANTED; 02771 } 02772 } 02773 else 02774 { 02775 /* request will not write anything */ 02776 if(export_client_match(hostaddr, 02777 ipstring, 02778 &(pexport->clients), 02779 pclient_found, 02780 EXPORT_OPTION_READ_ACCESS)) 02781 { 02782 if(pexport->access_type == ACCESSTYPE_MDONLY_RO || 02783 pexport->access_type == ACCESSTYPE_MDONLY) 02784 { 02785 LogFullDebug(COMPONENT_DISPATCH, 02786 "MDONLY export permission granted - no write"); 02787 return EXPORT_MDONLY_GRANTED; 02788 } 02789 else 02790 { 02791 LogFullDebug(COMPONENT_DISPATCH, 02792 "Read export permission granted"); 02793 return EXPORT_PERMISSION_GRANTED; 02794 } 02795 } 02796 else if(pexport->new_access_list_version && 02797 export_client_match(hostaddr, 02798 ipstring, 02799 &(pexport->clients), 02800 pclient_found, 02801 EXPORT_OPTION_MD_READ_ACCESS)) 02802 { 02803 pexport->access_type = ACCESSTYPE_MDONLY_RO; 02804 LogFullDebug(COMPONENT_DISPATCH, 02805 "MDONLY export permission granted new access list"); 02806 return EXPORT_MDONLY_GRANTED; 02807 } 02808 } 02809 LogFullDebug(COMPONENT_DISPATCH, 02810 "export permission denied"); 02811 return EXPORT_PERMISSION_DENIED; 02812 02813 #ifdef _USE_TIRPC_IPV6 02814 } 02815 else if(hostaddr->ss_family == AF_INET6) 02816 { 02817 static char ten_bytes_all_0[10]; 02818 static unsigned two_bytes_all_1 = 0xFFFF; 02819 memset(ten_bytes_all_0, 0, 10); 02820 struct sockaddr_in6 *psockaddr_in6 = (struct sockaddr_in6 *)hostaddr; 02821 02822 // if(isFulldebug(COMPONENT_DISPATCH)) 02823 { 02824 char txtaddrv6[100]; 02825 02826 inet_ntop(psockaddr_in6->sin6_family, 02827 psockaddr_in6->sin6_addr.s6_addr, txtaddrv6, 100); 02828 LogFullDebug(COMPONENT_DISPATCH, 02829 "Client has IPv6 adress = %s", txtaddrv6); 02830 } 02831 02832 /* If the client socket is IPv4, then it is wrapped into a ::ffff:a.b.c.d IPv6 address. We check this here 02833 * This kind of adress is shaped like this: 02834 * |---------------------------------------------------------------| 02835 * | 80 bits = 10 bytes | 16 bits = 2 bytes | 32 bits = 4 bytes | 02836 * |---------------------------------------------------------------| 02837 * | 0 | FFFF | IPv4 address | 02838 * |---------------------------------------------------------------| */ 02839 if(!memcmp(psockaddr_in6->sin6_addr.s6_addr, ten_bytes_all_0, 10) && 02840 !memcmp((psockaddr_in6->sin6_addr.s6_addr + 10), 02841 &two_bytes_all_1, 2)) 02842 { 02843 /* Use IP address as a string for wild character access checks. */ 02844 if(!ipvalid) 02845 { 02846 LogCrit(COMPONENT_DISPATCH, 02847 "Error: Could not convert the IPv6 address to a character string."); 02848 return EXPORT_PERMISSION_DENIED; 02849 } 02850 02851 /* This is an IPv4 address mapped to an IPv6 one. Extract the IPv4 address and proceed with IPv4 autentication */ 02852 memcpy(&hostaddr, (psockaddr_in6->sin6_addr.s6_addr + 12), 4); 02853 02854 /* Proceed with IPv4 dedicated function */ 02855 /* check if any root access export matches this client */ 02856 if((user_credentials->caller_uid == 0) && 02857 export_client_match(hostaddr, ipstring, &(pexport->clients), 02858 pclient_found, EXPORT_OPTION_ROOT)) 02859 return EXPORT_PERMISSION_GRANTED; 02860 /* else, check if any access only export matches this client */ 02861 if(proc_makes_write) 02862 { 02863 if (export_client_match(hostaddr, ipstring, &(pexport->clients), pclient_found, EXPORT_OPTION_WRITE_ACCESS)) 02864 return EXPORT_PERMISSION_GRANTED; 02865 else if (pexport->new_access_list_version && 02866 export_client_match(hostaddr, ipstring, 02867 &(pexport->clients), pclient_found, EXPORT_OPTION_MD_WRITE_ACCESS)) 02868 { 02869 pexport->access_type = ACCESSTYPE_MDONLY; 02870 return EXPORT_MDONLY_GRANTED; 02871 } 02872 } else { /* request will not write anything */ 02873 if (export_client_match(hostaddr, ipstring, &(pexport->clients), pclient_found, EXPORT_OPTION_READ_ACCESS)) 02874 return EXPORT_PERMISSION_GRANTED; 02875 else if (pexport->new_access_list_version && 02876 export_client_match(hostaddr, ipstring, 02877 &(pexport->clients), pclient_found, EXPORT_OPTION_MD_READ_ACCESS)) 02878 { 02879 pexport->access_type = ACCESSTYPE_MDONLY_RO; 02880 return EXPORT_MDONLY_GRANTED; 02881 } 02882 } 02883 } 02884 02885 if((user_credentials->caller_uid == 0) && 02886 export_client_matchv6(&(psockaddr_in6->sin6_addr), &(pexport->clients), 02887 pclient_found, EXPORT_OPTION_ROOT)) 02888 return EXPORT_PERMISSION_GRANTED; 02889 /* else, check if any access only export matches this client */ 02890 if(proc_makes_write) 02891 { 02892 if (export_client_matchv6(&(psockaddr_in6->sin6_addr), &(pexport->clients), pclient_found, EXPORT_OPTION_WRITE_ACCESS)) 02893 return EXPORT_PERMISSION_GRANTED; 02894 else if (pexport->new_access_list_version && export_client_matchv6(&(psockaddr_in6->sin6_addr), 02895 &(pexport->clients), pclient_found, EXPORT_OPTION_MD_WRITE_ACCESS)) 02896 { 02897 pexport->access_type = ACCESSTYPE_MDONLY; 02898 return EXPORT_MDONLY_GRANTED; 02899 } 02900 } 02901 else 02902 { /* request will not write anything */ 02903 if (export_client_matchv6(&(psockaddr_in6->sin6_addr), &(pexport->clients), pclient_found, EXPORT_OPTION_READ_ACCESS)) 02904 return EXPORT_PERMISSION_GRANTED; 02905 else if (pexport->new_access_list_version && export_client_matchv6(&(psockaddr_in6->sin6_addr), 02906 &(pexport->clients), pclient_found, EXPORT_OPTION_MD_READ_ACCESS)) 02907 { 02908 pexport->access_type = ACCESSTYPE_MDONLY_RO; 02909 return EXPORT_MDONLY_GRANTED; 02910 } 02911 } 02912 } 02913 #endif /* _USE_TIRPC_IPV6 */ 02914 02915 /* If this point is reached, no matching entry was found */ 02916 LogFullDebug(COMPONENT_DISPATCH, 02917 "export permission denied - no matching entry"); 02918 return EXPORT_PERMISSION_DENIED; 02919 02920 } /* nfs_export_check_access */ 02921 02933 int nfs_export_create_root_entry(exportlist_t * pexportlist) 02934 { 02935 exportlist_t *pcurrent = NULL; 02936 cache_inode_status_t cache_status; 02937 #ifdef _CRASH_RECOVERY_AT_STARTUP 02938 cache_content_status_t cache_content_status; 02939 #endif 02940 fsal_status_t fsal_status; 02941 cache_inode_fsal_data_t fsdata; 02942 fsal_handle_t fsal_handle; 02943 fsal_path_t exportpath_fsal; 02944 fsal_mdsize_t strsize = MNTPATHLEN + 1; 02945 cache_entry_t *pentry = NULL; 02946 02947 fsal_op_context_t context; 02948 fsal_staticfsinfo_t *pstaticinfo = NULL; 02949 fsal_export_context_t *export_context = NULL; 02950 02951 /* Get the context for FSAL super user */ 02952 fsal_status = FSAL_InitClientContext(&context); 02953 if(FSAL_IS_ERROR(fsal_status)) 02954 { 02955 LogCrit(COMPONENT_INIT, 02956 "Couldn't get the context for FSAL super user"); 02957 return FALSE; 02958 } 02959 02960 /* loop the export list */ 02961 02962 for(pcurrent = pexportlist; pcurrent != NULL; pcurrent = pcurrent->next) 02963 { 02964 02965 /* Build the FSAL path */ 02966 if(FSAL_IS_ERROR((fsal_status = FSAL_str2path(pcurrent->fullpath, 02967 strsize, &exportpath_fsal)))) 02968 return FALSE; 02969 02970 /* inits context for the current export entry */ 02971 02972 fsal_status = 02973 FSAL_BuildExportContext(&pcurrent->FS_export_context, &exportpath_fsal, 02974 pcurrent->FS_specific); 02975 02976 if(FSAL_IS_ERROR(fsal_status)) 02977 { 02978 LogCrit(COMPONENT_INIT, 02979 "Couldn't build export context for %s", 02980 pcurrent->fullpath); 02981 return FALSE; 02982 } 02983 02984 /* get the related client context */ 02985 fsal_status = FSAL_GetClientContext(&context, &pcurrent->FS_export_context, 0, 0, NULL, 0 ) ; 02986 02987 if(FSAL_IS_ERROR(fsal_status)) 02988 { 02989 LogCrit(COMPONENT_INIT, 02990 "Couldn't get the credentials for FSAL super user"); 02991 return FALSE; 02992 } 02993 02994 /* Lookup for the FSAL Path */ 02995 if(FSAL_IS_ERROR((fsal_status = FSAL_lookupPath(&exportpath_fsal, &context, &fsal_handle, NULL)))) 02996 { 02997 LogCrit(COMPONENT_INIT, 02998 "Couldn't access the root of the exported namespace, ExportId=%u Path=%s FSAL_ERROR=(%u,%u)", 02999 pcurrent->id, pcurrent->fullpath, fsal_status.major, 03000 fsal_status.minor); 03001 return FALSE; 03002 } 03003 03004 /* stores handle to the export entry */ 03005 03006 pcurrent->proot_handle = gsh_malloc(sizeof(fsal_handle_t)); 03007 03008 if(FSAL_IS_ERROR(fsal_status)) 03009 { 03010 LogCrit(COMPONENT_INIT, 03011 "Couldn't allocate memory"); 03012 return FALSE; 03013 } 03014 03015 *pcurrent->proot_handle = fsal_handle; 03016 export_context = &pcurrent->FS_export_context; 03017 pstaticinfo = export_context->fe_static_fs_info; 03018 if( ((pcurrent->options & EXPORT_OPTION_MAXREAD) != EXPORT_OPTION_MAXREAD )) 03019 { 03020 if ( pstaticinfo && pstaticinfo->maxread ) 03021 pcurrent->MaxRead = pstaticinfo->maxread; 03022 else 03023 pcurrent->MaxRead = LASTDEFAULT; 03024 } 03025 if( ((pcurrent->options & EXPORT_OPTION_MAXWRITE) != EXPORT_OPTION_MAXWRITE )) 03026 { 03027 if ( pstaticinfo && pstaticinfo->maxwrite ) 03028 pcurrent->MaxWrite = pstaticinfo->maxwrite; 03029 else 03030 pcurrent->MaxWrite = LASTDEFAULT; 03031 } 03032 LogFullDebug(COMPONENT_INIT, 03033 "Set MaxRead MaxWrite for Path=%s Options = 0x%x MaxRead = 0x%llX MaxWrite = 0x%llX", 03034 pcurrent->fullpath, pcurrent->options, 03035 (long long) pcurrent->MaxRead, 03036 (long long) pcurrent->MaxWrite); 03037 03038 /* Add this entry to the Cache Inode as a "root" entry */ 03039 fsdata.fh_desc.start = (caddr_t) &fsal_handle; 03040 fsdata.fh_desc.len = 0; 03041 (void) FSAL_ExpandHandle( 03042 #ifdef _USE_SHARED_FSAL 03043 context[pcurrent->fsalid].export_context, 03044 #else 03045 context.export_context, 03046 #endif 03047 FSAL_DIGEST_SIZEOF, 03048 &fsdata.fh_desc); 03049 03050 /* cache_inode_make_root returns a cache_entry with 03051 reference count of 2, where 1 is the sentinel value of 03052 a cache entry in the hash table. The export list in 03053 this case owns the extra reference, but other users of 03054 cache_inode_make_root MUST put the entry. In the future 03055 if functionality is added to dynamically add and remove 03056 export entries, then the function to remove an export 03057 entry MUST put the extra reference. */ 03058 03059 if((pentry = cache_inode_make_root(&fsdata, 03060 &context, 03061 &cache_status)) == NULL) 03062 { 03063 LogCrit(COMPONENT_INIT, 03064 "Error when creating root cached entry for %s, export_id=%d, cache_status=%d", 03065 pcurrent->fullpath, pcurrent->id, cache_status); 03066 return FALSE; 03067 } 03068 else 03069 LogInfo(COMPONENT_INIT, 03070 "Added root entry for path %s on export_id=%d", 03071 pcurrent->fullpath, pcurrent->id); 03072 03073 /* Set the pentry as a referral if needed */ 03074 if(strcmp(pcurrent->referral, "")) 03075 { 03076 /* Set the cache_entry object as a referral by setting the 'referral' field */ 03077 pentry->object.dir.referral = pcurrent->referral; 03078 LogInfo(COMPONENT_INIT, "A referral is set : %s", 03079 pentry->object.dir.referral); 03080 } 03081 } 03082 03083 /* Note: As mentioned above, we are returning with an extra 03084 reference to the root entry. This reference is owned by the 03085 export list. If we ever have a function to remove objects from 03086 the export list, it must return this extra reference. */ 03087 03088 return TRUE; 03089 03090 } /* nfs_export_create_root_entry */ 03091 03092 /* cleans up the export content */ 03093 int CleanUpExportContext(fsal_export_context_t * p_export_context) 03094 { 03095 03096 FSAL_CleanUpExportContext(p_export_context); 03097 03098 return TRUE; 03099 } 03100 03101 03102 /* Frees current export entry and returns next export entry. */ 03103 exportlist_t *RemoveExportEntry(exportlist_t * exportEntry) 03104 { 03105 exportlist_t *next; 03106 03107 if (exportEntry == NULL) 03108 return NULL; 03109 03110 next = exportEntry->next; 03111 03112 if (exportEntry->proot_handle != NULL) 03113 gsh_free(exportEntry->proot_handle); 03114 03115 if (exportEntry->worker_stats != NULL) 03116 gsh_free(exportEntry->worker_stats); 03117 03118 gsh_free(exportEntry); 03119 return next; 03120 } 03121 03122 exportlist_t *GetExportEntry(char *exportPath) 03123 { 03124 exportlist_t *pexport = NULL; 03125 exportlist_t *p_current_item = NULL; 03126 char tmplist_path[MAXPATHLEN]; 03127 char tmpexport_path[MAXPATHLEN]; 03128 int found = 0; 03129 03130 pexport = nfs_param.pexportlist; 03131 03132 /* 03133 * Find the export for the dirname (using as well Path or Tag ) 03134 */ 03135 for(p_current_item = pexport; p_current_item != NULL; 03136 p_current_item = p_current_item->next) 03137 { 03138 LogDebug(COMPONENT_CONFIG, "full path %s, export path %s", 03139 p_current_item->fullpath, exportPath); 03140 03141 /* Make sure the path in export entry ends with a '/', if not adds one */ 03142 if(p_current_item->fullpath[strlen(p_current_item->fullpath) - 1] == '/') 03143 strncpy(tmplist_path, p_current_item->fullpath, MAXPATHLEN); 03144 else 03145 snprintf(tmplist_path, MAXPATHLEN, "%s/", p_current_item->fullpath); 03146 03147 /* Make sure that the argument from MNT ends with a '/', if not adds one */ 03148 if(exportPath[strlen(exportPath) - 1] == '/') 03149 strncpy(tmpexport_path, exportPath, MAXPATHLEN); 03150 else 03151 snprintf(tmpexport_path, MAXPATHLEN, "%s/", exportPath); 03152 03153 /* Is tmplist_path a subdirectory of tmpexport_path ? */ 03154 if(!strncmp(tmplist_path, tmpexport_path, strlen(tmplist_path))) 03155 { 03156 found = 1; 03157 break; 03158 } 03159 } 03160 03161 if(found) 03162 { 03163 LogDebug(COMPONENT_CONFIG, "returning export %s", p_current_item->fullpath); 03164 return p_current_item; 03165 } 03166 else 03167 { 03168 LogDebug(COMPONENT_CONFIG, "returning export NULL"); 03169 return NULL; 03170 } 03171 }