/** * * nfs_ip_name_get: Tries to get an entry for ip_name cache. * * Tries to get an entry for ip_name cache. * * @param ipaddr [IN] the ip address requested * @param hostname [OUT] the hostname * * @return the result previously set if *pstatus == IP_NAME_SUCCESS * */ int nfs_ip_name_get(sockaddr_t *ipaddr, char *hostname, size_t size) { struct gsh_buffdesc buffkey; struct gsh_buffdesc buffval; nfs_ip_name_t *nfs_ip_name; char ipstring[SOCK_NAME_MAX + 1]; sprint_sockip(ipaddr, ipstring, sizeof(ipstring)); buffkey.addr = ipaddr; buffkey.len = sizeof(sockaddr_t); if (HashTable_Get(ht_ip_name, &buffkey, &buffval) == HASHTABLE_SUCCESS) { nfs_ip_name = buffval.addr; strmaxcpy(hostname, nfs_ip_name->hostname, size); LogFullDebug(COMPONENT_DISPATCH, "Cache get hit for %s->%s", ipstring, nfs_ip_name->hostname); return IP_NAME_SUCCESS; } LogFullDebug(COMPONENT_DISPATCH, "Cache get miss for %s", ipstring); return IP_NAME_NOT_FOUND; } /* nfs_ip_name_get */
/* * Given a (possibly unqualified) hostname, * return the fully qualified (lower-case!) hostname */ static int get_full_hostname(const char *inhost, char *outhost, int outhostlen) { struct addrinfo *addrs = NULL; struct addrinfo hints; int retval; char *c; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_CANONNAME; /* Get full target hostname */ retval = getaddrinfo(inhost, NULL, &hints, &addrs); if (retval) { printerr(1, "%s while getting full hostname for '%s'\n", gai_strerror(retval), inhost); goto out; } strmaxcpy(outhost, addrs->ai_canonname, outhostlen); freeaddrinfo(addrs); for (c = outhost; *c != '\0'; c++) *c = tolower(*c); printerr(3, "Full hostname for '%s' is '%s'\n", inhost, outhost); retval = 0; out: return retval; }
void nfs_set_client_location(nfs_client_id_t *pclientid, const clientaddr4 *addr4) { pclientid->cid_cb.cid_addr.nc = nfs_netid_to_nc(addr4->r_netid); if(strmaxcpy(pclientid->cid_cb.cid_client_r_addr, addr4->r_addr, sizeof(pclientid->cid_cb.cid_client_r_addr)) == -1) { LogCrit(COMPONENT_NFS_CB, "cid_client_r_addr %s too long", pclientid->cid_cb.cid_client_r_addr); } setup_client_saddr(pclientid, pclientid->cid_cb.cid_client_r_addr); }
/* * Initialize subsystem */ void nfs_rpc_cb_pkginit(void) { char localmachine[MAXHOSTNAMELEN]; /* Create a pool of rpc_call_t */ rpc_call_pool = pool_init("RPC Call Pool", sizeof(rpc_call_t), pool_basic_substrate, NULL, nfs_rpc_init_call, NULL); if(!(rpc_call_pool)) { LogCrit(COMPONENT_INIT, "Error while allocating rpc call pool"); LogError(COMPONENT_INIT, ERR_SYS, ERR_MALLOC, errno); Fatal(); } /* get host name */ if(gethostname(localmachine, sizeof(localmachine)) != 0) { LogCrit(COMPONENT_INIT, "Failed to get local host name"); } else if(strmaxcpy(host_name, localmachine, sizeof(host_name)) == -1) { LogCrit(COMPONENT_INIT, "local host name %s too long", localmachine); } /* ccache */ nfs_rpc_cb_init_ccache(nfs_param.krb5_param.ccache_dir); /* sanity check GSSAPI */ if (gssd_check_mechs() != 0) LogCrit(COMPONENT_INIT, "sanity check: gssd_check_mechs() failed"); return; }
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETCLIENTID4args * const arg_SETCLIENTID4 = &op->nfs_argop4_u.opsetclientid; SETCLIENTID4res * const res_SETCLIENTID4 = &resp->nfs_resop4_u.opsetclientid; clientaddr4 * const res_SETCLIENTID4_INUSE = &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using; char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; char str_client_addr[SOCK_NAME_MAX + 1]; nfs_client_record_t *client_record; nfs_client_id_t *conf; nfs_client_id_t *unconf; clientid4 clientid; verifier4 verifier; sockaddr_t client_addr; int rc; resp->resop = NFS4_OP_SETCLIENTID; if (data->minorversion > 0) { res_SETCLIENTID4->status = NFS4ERR_NOTSUPP; return res_SETCLIENTID4->status; } copy_xprt_addr(&client_addr, data->req->rq_xprt); if (isDebug(COMPONENT_CLIENTID)) { sprint_sockip(&client_addr, str_client_addr, sizeof(str_client_addr)); DisplayOpaqueValue(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, str_client); sprint_mem(str_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); } LogDebug(COMPONENT_CLIENTID, "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u", str_client_addr, str_client, str_verifier, arg_SETCLIENTID4->callback.cb_program, arg_SETCLIENTID4->callback.cb_location.r_addr, arg_SETCLIENTID4->callback.cb_location.r_netid, arg_SETCLIENTID4->callback_ident); /* Do we already have one or more records for client id (x)? */ client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, 0, 0); if (client_record == NULL) { /* Some major failure */ LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed"); res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT; return res_SETCLIENTID4->status; } /* The following checks are based on RFC3530bis draft 16 * * This attempts to implement the logic described in * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE * 1, CASE 2, CASE 3, CASE 4, and CASE 5. */ pthread_mutex_lock(&client_record->cr_mutex); if (isFullDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_record(client_record, str); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p " "cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } conf = client_record->cr_confirmed_rec; if (conf != NULL) { /* Need a reference to the confirmed record for below */ inc_client_id_ref(conf); if (!nfs_compare_clientcred(&conf->cid_credential, &data->credential) || !cmp_sockaddr(&conf->cid_client_addr, &client_addr, true)) { /* CASE 1: * * Confirmed record exists and not the same principal */ if (isDebug(COMPONENT_CLIENTID)) { char confirmed_addr[SOCK_NAME_MAX + 1]; sprint_sockip(&conf->cid_client_addr, confirmed_addr, sizeof(confirmed_addr)); LogDebug(COMPONENT_CLIENTID, "Confirmed ClientId %" PRIx64 "->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", conf->cid_clientid, str_client, confirmed_addr); } res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE; res_SETCLIENTID4_INUSE->r_netid = (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc] .netid; res_SETCLIENTID4_INUSE->r_addr = gsh_strdup(conf->cid_cb.v40.cb_client_r_addr); /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); goto out; } /* Check if confirmed record is for (v, x, c, l, s) */ if (memcmp (arg_SETCLIENTID4->client.verifier, conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /* CASE 2: * * A confirmed record exists for this long * form client id and verifier. * * Consider this to be a possible update of * the call-back information. * * Remove any pre-existing unconfirmed record * for (v, x, c). * * Return the same short form client id (c), * but a new setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "Update ClientId %" PRIx64 "->%s", conf->cid_clientid, str_client); clientid = conf->cid_clientid; new_clientid_verifier(verifier); } else { /* Must be CASE 3 or CASE 4 * * Confirmed record is for (u, x, c, l, s). * * These are actually the same, doesn't really * matter if an unconfirmed record exists or * not. Any existing unconfirmed record will * be removed and a new unconfirmed record * added. * * Return a new short form clientid (d) and a * new setclientid_confirm verifier (t). (Note * the spec calls the values e and r for CASE * 4). */ LogFullDebug(COMPONENT_CLIENTID, "Replace ClientId %" PRIx64 "->%s", conf->cid_clientid, str_client); clientid = new_clientid(); new_clientid_verifier(verifier); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); } else { /* CASE 5: * * * Remove any existing unconfirmed record. * * Return a new short form clientid (d) and a new * setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "New client"); clientid = new_clientid(); new_clientid_verifier(verifier); } /* At this point, no matter what the case was above, we should * remove any pre-existing unconfirmed record. */ unconf = client_record->cr_unconfirmed_rec; if (unconf != NULL) { /* Delete the unconfirmed clientid record. Because we * have the cr_mutex, we have won any race to deal * with this clientid record (whether we raced with a * SETCLIENTID_CONFIRM or the reaper thread (if either * of those operations had won the race, * cr_punconfirmed_id would have been NULL). */ if (isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; display_client_id_rec(unconf, str); LogDebug(COMPONENT_CLIENTID, "Replacing %s", str); } /* unhash the clientid record */ remove_unconfirmed_client_id(unconf); unconf = NULL; } /* Now we can proceed to build the new unconfirmed record. We * have determined the clientid and setclientid_confirm values * above. */ unconf = create_client_id(clientid, client_record, &client_addr, &data->credential, 0); if (unconf == NULL) { /* Error already logged, return */ res_SETCLIENTID4->status = NFS4ERR_RESOURCE; goto out; } if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr, arg_SETCLIENTID4->callback.cb_location.r_addr, sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) { LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long", arg_SETCLIENTID4->callback.cb_location.r_addr); res_SETCLIENTID4->status = NFS4ERR_INVAL; goto out; } nfs_set_client_location(unconf, &arg_SETCLIENTID4->callback.cb_location); memcpy(unconf->cid_incoming_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier)); unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program; unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident; rc = nfs_client_id_insert(unconf); if (rc != CLIENT_ID_SUCCESS) { /* Record is already freed, return. */ res_SETCLIENTID4->status = clientid_error_to_nfsstat(rc); goto out; } if (isDebug(COMPONENT_CLIENTID)) { char str[HASHTABLE_DISPLAY_STRLEN]; sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(unconf, str); LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s", str_verifier, str); } res_SETCLIENTID4->status = NFS4_OK; res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid; memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm, &verifier, NFS4_VERIFIER_SIZE); out: pthread_mutex_unlock(&client_record->cr_mutex); /* Release our reference to the client record */ dec_client_record_ref(client_record); return res_SETCLIENTID4->status; }
/** * * nfs_Add_MountList_Entry: Adds a client to the mount list. * * Adds a client to the mount list. * * @param hostname [IN] the hostname for the client * @param dirpath [IN] the mounted path * * @return 1 if successful, 0 otherwise * */ int nfs_Add_MountList_Entry(char *hostname, char *dirpath) { #ifndef _NO_MOUNT_LIST mountlist pnew_mnt_list_entry; #endif /* Sanity check */ if(hostname == NULL || dirpath == NULL) return 0; #ifndef _NO_MOUNT_LIST /* Allocate the new entry */ if((pnew_mnt_list_entry = gsh_calloc(1, sizeof(struct mountbody))) == NULL) return 0; if((pnew_mnt_list_entry->ml_hostname = gsh_calloc(1, MAXHOSTNAMELEN + 1)) == NULL) { gsh_free(pnew_mnt_list_entry); return 0; } if((pnew_mnt_list_entry->ml_directory = gsh_calloc(1, MAXPATHLEN + 1)) == NULL) { gsh_free(pnew_mnt_list_entry->ml_hostname); gsh_free(pnew_mnt_list_entry); return 0; } /* Copy the data */ if (strmaxcpy(pnew_mnt_list_entry->ml_hostname, hostname, MAXHOSTNAMELEN) == -1) { gsh_free(pnew_mnt_list_entry->ml_directory); gsh_free(pnew_mnt_list_entry->ml_hostname); gsh_free(pnew_mnt_list_entry); return 0; } if (strmaxcpy(pnew_mnt_list_entry->ml_directory, dirpath, MAXPATHLEN) == -1) { gsh_free(pnew_mnt_list_entry->ml_directory); gsh_free(pnew_mnt_list_entry->ml_hostname); gsh_free(pnew_mnt_list_entry); return 0; } /* initialize next pointer */ pnew_mnt_list_entry->ml_next = NULL; /* This should occur only for the first mount */ if(MNT_List_head == NULL) { MNT_List_head = pnew_mnt_list_entry; } /* Append to the tail of the list */ if(MNT_List_tail == NULL) MNT_List_tail = pnew_mnt_list_entry; else { MNT_List_tail->ml_next = pnew_mnt_list_entry; MNT_List_tail = pnew_mnt_list_entry; } if(isFullDebug(COMPONENT_NFSPROTO)) nfs_Print_MountList(); #endif return 1; }
int main(int argc, char *argv[]) { int fg = 0; int verbosity = 0; int rpc_verbosity = 0; int opt; int i; extern char *optarg; char *progname; memset(ccachesearch, 0, sizeof(ccachesearch)); while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) { switch (opt) { case 'f': fg = 1; break; case 'm': /* Accept but ignore this. Now the default. */ break; case 'M': use_memcache = 1; break; case 'n': root_uses_machine_creds = 0; break; case 'v': verbosity++; break; case 'r': rpc_verbosity++; break; case 'p': strmaxcpy(pipefs_dir, optarg, sizeof(pipefs_dir)); if (pipefs_dir[sizeof(pipefs_dir)-1] != '\0') errx(1, "pipefs path name too long"); break; case 'k': strmaxcpy(keytabfile, optarg, sizeof(keytabfile)); if (keytabfile[sizeof(keytabfile)-1] != '\0') errx(1, "keytab path name too long"); break; case 'd': strmaxcpy(ccachedir, optarg, sizeof(ccachedir)); if (ccachedir[sizeof(ccachedir)-1] != '\0') errx(1, "ccachedir path name too long"); break; case 't': context_timeout = atoi(optarg); break; case 'R': preferred_realm = strdup(optarg); break; default: usage(argv[0]); break; } } i = 0; ccachesearch[i++] = strtok(ccachedir, ":"); do { ccachesearch[i++] = strtok(NULL, ":"); } while (ccachesearch[i-1] != NULL && i < GSSD_MAX_CCACHE_SEARCH); if (preferred_realm == NULL) gssd_k5_get_default_realm(&preferred_realm); if ((progname = strrchr(argv[0], '/'))) progname++; else progname = argv[0]; initerr(progname, verbosity, fg); #ifdef HAVE_AUTHGSS_SET_DEBUG_LEVEL if (verbosity && rpc_verbosity == 0) rpc_verbosity = verbosity; authgss_set_debug_level(rpc_verbosity); #else if (rpc_verbosity > 0) printerr(0, "Warning: rpcsec_gss library does not " "support setting debug level\n"); #endif if (gssd_check_mechs() != 0) errx(1, "Problem with gssapi library"); if (!fg && daemon(0, 0) < 0) errx(1, "fork"); signal(SIGINT, sig_die); signal(SIGTERM, sig_die); signal(SIGHUP, sig_hup); gssd_run(); printerr(0, "gssd_run returned!\n"); abort(); }
/* * Create, initialize, and add a new ple structure to the global list */ static struct gssd_k5_kt_princ *new_ple(krb5_context context, krb5_principal princ) { struct gssd_k5_kt_princ *ple = NULL, *p; krb5_error_code code; char *default_realm; int is_default_realm = 0; ple = gsh_malloc(sizeof(struct gssd_k5_kt_princ)); if (ple == NULL) goto outerr; memset(ple, 0, sizeof(*ple)); #ifdef HAVE_KRB5 ple->realm = gsh_malloc(princ->realm.length + 1); if (ple->realm == NULL) goto outerr; strmaxcpy(ple->realm, princ->realm.data, princ->realm.length); ple->realm[princ->realm.length] = '\0'; #else ple->realm = gsh_strdup(princ->realm); if (ple->realm == NULL) goto outerr; #endif code = krb5_copy_principal(context, princ, &ple->princ); if (code) goto outerr; /* * Add new entry onto the list (if this is the default * realm, always add to the front of the list) */ code = krb5_get_default_realm(context, &default_realm); if (code == 0) { if (strcmp(ple->realm, default_realm) == 0) is_default_realm = 1; k5_free_default_realm(context, default_realm); } if (is_default_realm) { ple->next = gssd_k5_kt_princ_list; gssd_k5_kt_princ_list = ple; } else { p = gssd_k5_kt_princ_list; while (p != NULL && p->next != NULL) p = p->next; if (p == NULL) gssd_k5_kt_princ_list = ple; else p->next = ple; } return ple; outerr: if (ple) { if (ple->realm) gsh_free(ple->realm); gsh_free(ple); } return NULL; }
/** * * nfs_read_gidmap_conf: reads the configuration for the GID_MAPPER Cache * * Reads the configuration for the GID_MAPPER Cache * * @param in_config [IN] configuration file handle * @param pparam [OUT] read parameters * * @return 0 if ok, -1 if not, 1 is stanza is not there. * */ int nfs_read_gidmap_conf(config_file_t in_config, nfs_idmap_cache_parameter_t * pparam) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; /* Is the config tree initialized ? */ if(in_config == NULL || pparam == NULL) return -1; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_LABEL_GID_MAPPER)) == NULL) { LogDebug(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_CLIENT_ID); return 1; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogDebug(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_CLIENT_ID); return 1; } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogCrit(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_GID_MAPPER); return -1; } if(!strcasecmp(key_name, "Index_Size")) { pparam->hash_param.index_size = atoi(key_value); } else if(!strcasecmp(key_name, "Alphabet_Length")) { pparam->hash_param.alphabet_length = atoi(key_value); } else if(!strcasecmp(key_name, "Map")) { if(strmaxcpy(pparam->mapfile, key_value, sizeof(pparam->mapfile)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else { LogCrit(COMPONENT_CONFIG, "Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_GID_MAPPER); return -1; } } return 0; } /* nfs_read_gidmap_conf */
/** * * nfs_read_core_conf: read the configuration ite; for the worker theads. * * Reads the configuration ite; for the worker theads. * * @param in_config [IN] configuration file handle * @param pparam [OUT] read parameters * * @return 0 if ok, -1 if failed, 1 is stanza is not there. * */ int nfs_read_core_conf(config_file_t in_config, nfs_core_parameter_t * pparam) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; /* Is the config tree initialized ? */ if(in_config == NULL || pparam == NULL) return CACHE_INODE_INVALID_ARGUMENT; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_LABEL_NFS_CORE)) == NULL) { LogDebug(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_NFS_CORE); return 1; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogDebug(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_NFS_CORE); return 1; } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogCrit(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_NFS_CORE); return CACHE_INODE_INVALID_ARGUMENT; } if(!strcasecmp(key_name, "Nb_Worker")) { pparam->nb_worker = atoi(key_value); } else if(!strcasecmp(key_name, "Nb_Call_Before_Queue_Avg")) { pparam->nb_call_before_queue_avg = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_Disabled")) { pparam->drc.disabled = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Npart")) { pparam->drc.tcp.npart = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Size")) { pparam->drc.tcp.size = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Cachesz")) { pparam->drc.tcp.cachesz = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Hiwat")) { pparam->drc.tcp.hiwat = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Recycle_Npart")) { pparam->drc.tcp.recycle_npart = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Recycle_Expire_S")) { pparam->drc.tcp.recycle_expire_s = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_TCP_Checksum")) { pparam->drc.tcp.checksum = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "DRC_UDP_Npart")) { pparam->drc.udp.npart = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_UDP_Size")) { pparam->drc.udp.size = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_UDP_Cachesz")) { pparam->drc.udp.cachesz = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_UDP_Hiwat")) { pparam->drc.udp.hiwat = atoi(key_value); } else if(!strcasecmp(key_name, "DRC_UDP_Checksum")) { pparam->drc.udp.checksum = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "DupReq_Expiration")) { pparam->expiration_dupreq = atoi(key_value); } else if(!strcasecmp(key_name, "Dispatch_Max_Reqs")) { pparam->dispatch_max_reqs = atoi(key_value); } else if(!strcasecmp(key_name, "Dispatch_Max_Reqs_Xprt")) { pparam->dispatch_max_reqs_xprt = atoi(key_value); } else if(!strcasecmp(key_name, "Drop_IO_Errors")) { pparam->drop_io_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Drop_Inval_Errors")) { pparam->drop_inval_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Drop_Delay_Errors")) { pparam->drop_delay_errors = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "NFS_Port")) { pparam->port[P_NFS] = (unsigned short)atoi(key_value); } else if(!strcasecmp(key_name, "MNT_Port")) { pparam->port[P_MNT] = (unsigned short)atoi(key_value); } else if(!strcasecmp(key_name, "NLM_Port")) { #ifdef _USE_NLM pparam->port[P_NLM] = (unsigned short)atoi(key_value); #endif } else if(!strcasecmp(key_name, "Rquota_Port")) { #ifdef _USE_RQUOTA pparam->port[P_RQUOTA] = (unsigned short)atoi(key_value); #endif } else if(!strcasecmp(key_name, "NFS_Program")) { pparam->program[P_NFS] = atoi(key_value); } else if(!strcasecmp(key_name, "MNT_Program")) { pparam->program[P_MNT] = atoi(key_value); } else if(!strcasecmp(key_name, "NLM_Program")) { #ifdef _USE_NLM pparam->program[P_NLM] = atoi(key_value); #endif } else if(!strcasecmp(key_name, "Rquota_Program")) { #ifdef _USE_RQUOTA pparam->program[P_RQUOTA] = atoi(key_value); #endif } else if(!strcasecmp(key_name, "NFS_Protocols")) { # define MAX_NFSPROTO 10 /* large enough !!! */ char *nfsvers_list[MAX_NFSPROTO]; int idx, count; /* reset nfs versions flags (clean defaults) */ pparam->core_options &= ~(CORE_OPTION_ALL_VERS); /* fill nfs vers list with NULL pointers */ memset(nfsvers_list, 0, sizeof(nfsvers_list)); /* * Search for coma-separated list of nfsprotos */ count = nfs_ParseConfLine(nfsvers_list, MAX_NFSPROTO, 0, key_value, ','); if(count < 0) { LogCrit(COMPONENT_CONFIG, "NFS_Protocols list too long (>%d)", MAX_NFSPROTO); return -1; } /* add each Nfs protocol flag to the option field. */ for(idx = 0; idx < count; idx++) { if(!strcmp(nfsvers_list[idx], "4")) { pparam->core_options |= CORE_OPTION_NFSV4; } else if(!strcmp(nfsvers_list[idx], "2")) { pparam->core_options |= CORE_OPTION_NFSV2; } else if(!strcmp(nfsvers_list[idx], "3")) { pparam->core_options |= CORE_OPTION_NFSV3; } else { LogCrit(COMPONENT_CONFIG, "Invalid NFS Protocol \"%s\". Values can be: 2, 3, 4.", nfsvers_list[idx]); return -1; } } /* check that at least one nfs protocol has been specified */ if((pparam->core_options & (CORE_OPTION_ALL_VERS)) == 0) { LogCrit(COMPONENT_CONFIG, "Empty NFS_Protocols list"); return -1; } } else if(!strcasecmp(key_name, "Bind_Addr")) { int rc; memset(&pparam->bind_addr.sin_addr, 0, sizeof(pparam->bind_addr.sin_addr)); rc = inet_pton(AF_INET, key_value, &pparam->bind_addr.sin_addr); if(rc <= 0) { /* Revert to INADDR_ANY in case of any error */ pparam->bind_addr.sin_addr.s_addr = INADDR_ANY; /* All the interfaces on the machine are used */ } } else if(!strcasecmp(key_name, "Core_Dump_Size")) { pparam->core_dump_size = atol(key_value); } else if(!strcasecmp(key_name, "Nb_Max_Fd")) { pparam->nb_max_fd = atoi(key_value); } else if(!strcasecmp(key_name, "Stats_File_Path")) { if(strmaxcpy(pparam->stats_file_path, key_value, sizeof(pparam->stats_file_path)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp(key_name, "Stats_Update_Delay")) { pparam->stats_update_delay = atoi(key_value); } else if(!strcasecmp(key_name, "Long_Processing_Threshold")) { pparam->long_processing_threshold = atoi(key_value); pparam->long_processing_threshold_msec = pparam->long_processing_threshold * MSEC_PER_SEC; } else if(!strcasecmp( key_name, "Decoder_Fridge_Expiration_Delay" ) ) { pparam->decoder_fridge_expiration_delay = atoi(key_value); } else if(!strcasecmp(key_name, "Dump_Stats_Per_Client")) { pparam->dump_stats_per_client = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Stats_Per_Client_Directory")) { if(strmaxcpy(pparam->stats_per_client_directory, key_value, sizeof(pparam->stats_per_client_directory)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp( key_name, "MaxRPCSendBufferSize" ) ) { pparam->max_send_buffer_size = atoi(key_value); } else if(!strcasecmp( key_name, "MaxRPCRecvBufferSize" ) ) { pparam->max_recv_buffer_size = atoi(key_value); } #ifdef _USE_NLM else if(!strcasecmp( key_name, "NSM_Use_Caller_Name" ) ) { pparam->nsm_use_caller_name = StrToBoolean(key_value); } #endif else if(!strcasecmp(key_name, "Clustered")) { pparam->clustered = StrToBoolean(key_value); } else { LogCrit(COMPONENT_CONFIG, "Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_NFS_CORE); return -1; } } return 0; } /* nfs_read_core_conf */
int nfs_get_fsalpathlib_conf(char *configPath, path_str_t * PathLib, unsigned int *plen) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; unsigned int found = FALSE; config_file_t config_struct; unsigned int index = 0 ; /* Is the config tree initialized ? */ if(configPath == NULL || PathLib == NULL) LogFatal(COMPONENT_CONFIG, "nfs_get_fsalpathlib_conf configPath=%p PathLib=%p", configPath, PathLib); config_struct = config_ParseFile(configPath); if(!config_struct) LogFatal(COMPONENT_CONFIG, "Error while parsing %s: %s", configPath, config_GetErrorMsg()); /* Get the config BLOCK */ if((block = config_FindItemByName(config_struct, CONF_LABEL_NFS_CORE)) == NULL) { LogFatal(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_NFS_CORE); } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogFatal(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_NFS_CORE); } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogFatal(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_NFS_CORE); } if(!strcasecmp(key_name, "FSAL_Shared_Library")) { if(strmaxcpy(PathLib[index], key_value, sizeof(PathLib[index])) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } index += 1 ; found = TRUE; /* Do not exceed array size */ if( index == *plen ) break ; } } if(!found) { LogFatal(COMPONENT_CONFIG, "FSAL_Shared_Library not found"); return 1; } *plen = index ; return 0; } /* nfs_get_fsalpathlib_conf */
/** * * nfs_read_version4_conf: read the configuration for NFSv4 stuff * * Read the configuration for NFSv4 stuff. * * @param in_config [IN] configuration file handle * @param pparam [OUT] read parameters * * @return 0 if ok, -1 if failed,1 is stanza is not there * */ int nfs_read_version4_conf(config_file_t in_config, nfs_version4_parameter_t * pparam) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; /* Is the config tree initialized ? */ if(in_config == NULL || pparam == NULL) return -1; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_LABEL_NFS_VERSION4)) == NULL) { LogDebug(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_NFS_VERSION4); return 1; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogDebug(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_NFS_VERSION4); return 1; } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogCrit(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_NFS_VERSION4); return -1; } if(!strcasecmp(key_name, "Lease_Lifetime")) { pparam->lease_lifetime = atoi(key_value); } else if(!strcasecmp(key_name, "DomainName")) { if(strmaxcpy(pparam->domainname, key_value, sizeof(pparam->domainname)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp(key_name, "IdmapConf")) { if(strmaxcpy(pparam->idmapconf, key_value, sizeof(pparam->idmapconf)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp(key_name, "FH_Expire")) { pparam->fh_expire = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Returns_ERR_FH_EXPIRED")) { pparam->returns_err_fh_expired = StrToBoolean(key_value); } else if(!strcasecmp(key_name, "Return_Bad_Stateid")) { pparam->return_bad_stateid = StrToBoolean(key_value); } else { LogCrit(COMPONENT_CONFIG, "Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_NFS_VERSION4); return -1; } } return 0; } /* nfs_read_version4_conf */
/** * * nfs_read_krb5_conf: read the configuration for krb5 stuff * * Read the configuration for krb5 stuff. * * @param in_config [IN] configuration file handle * @param pparam [OUT] read parameters * * @return 0 if ok, -1 if failed,1 is stanza is not there * */ int nfs_read_krb5_conf(config_file_t in_config, nfs_krb5_parameter_t * pparam) { int var_max; int var_index; int err; char *key_name; char *key_value; config_item_t block; /* Is the config tree initialized ? */ if(in_config == NULL || pparam == NULL) return -1; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_LABEL_NFS_KRB5)) == NULL) { LogDebug(COMPONENT_CONFIG, "Cannot read item \"%s\" from configuration file", CONF_LABEL_NFS_KRB5); return 1; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { /* Expected to be a block */ LogDebug(COMPONENT_CONFIG, "Item \"%s\" is expected to be a block", CONF_LABEL_NFS_KRB5); return 1; } var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { config_item_t item; item = config_GetItemByIndex(block, var_index); /* Get key's name */ if((err = config_GetKeyValue(item, &key_name, &key_value)) != 0) { LogCrit(COMPONENT_CONFIG, "Error reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_NFS_KRB5); return -1; } if(!strcasecmp(key_name, "PrincipalName")) { if(strmaxcpy(pparam->svc.principal, key_value, sizeof(pparam->svc.principal)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp(key_name, "KeytabPath")) { if(strmaxcpy(pparam->keytab, key_value, sizeof(pparam->keytab)) == -1) { LogCrit(COMPONENT_CONFIG, "%s=\"%s\" too long", key_name, key_value); } } else if(!strcasecmp(key_name, "Active_krb5")) { pparam->active_krb5 = StrToBoolean(key_value); } else { LogCrit(COMPONENT_CONFIG, "Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_NFS_KRB5); return -1; } } return 0; } /* nfs_read_krb5_conf */
int nfs_ip_name_add(sockaddr_t *ipaddr, char *hostname, size_t size) { struct gsh_buffdesc buffkey; struct gsh_buffdesc buffdata; nfs_ip_name_t *nfs_ip_name = NULL; sockaddr_t *pipaddr = NULL; struct timeval tv0, tv1, dur; int rc; char ipstring[SOCK_NAME_MAX + 1]; nfs_ip_name = gsh_malloc(sizeof(nfs_ip_name_t)); pipaddr = gsh_malloc(sizeof(sockaddr_t)); /* I have to keep an integer as key, I wil use the pointer buffkey->addr * for this, this also means that buffkey->len will be 0 */ memcpy(pipaddr, ipaddr, sizeof(sockaddr_t)); buffkey.addr = pipaddr; buffkey.len = sizeof(sockaddr_t); gettimeofday(&tv0, NULL); rc = getnameinfo((struct sockaddr *)pipaddr, sizeof(sockaddr_t), nfs_ip_name->hostname, sizeof(nfs_ip_name->hostname), NULL, 0, 0); gettimeofday(&tv1, NULL); timersub(&tv1, &tv0, &dur); sprint_sockip(pipaddr, ipstring, sizeof(ipstring)); /* display warning if DNS resolution took more that 1.0s */ if (dur.tv_sec >= 1) { LogEvent(COMPONENT_DISPATCH, "Warning: long DNS query for %s: %u.%06u sec", ipstring, (unsigned int)dur.tv_sec, (unsigned int)dur.tv_usec); } /* Ask for the name to be cached */ if (rc != 0) { strmaxcpy(nfs_ip_name->hostname, ipstring, sizeof(nfs_ip_name->hostname)); LogEvent(COMPONENT_DISPATCH, "Cannot resolve address %s, error %s, using %s as hostname", ipstring, gai_strerror(rc), nfs_ip_name->hostname); } LogDebug(COMPONENT_DISPATCH, "Inserting %s->%s to addr cache", ipstring, nfs_ip_name->hostname); /* I build the data with the request pointer * that should be in state 'IN USE' */ nfs_ip_name->timestamp = time(NULL); buffdata.addr = nfs_ip_name; buffdata.len = sizeof(nfs_ip_name_t); if (HashTable_Set(ht_ip_name, &buffkey, &buffdata) != HASHTABLE_SUCCESS) return IP_NAME_INSERT_MALLOC_ERROR; /* Copy the value for the caller */ strmaxcpy(hostname, nfs_ip_name->hostname, size); return IP_NAME_SUCCESS; } /* nfs_ip_name_add */
int get_snmpadm_conf(config_file_t in_config, external_tools_parameter_t * out_parameter) { int err; int var_max, var_index; char *key_name; char *key_value; config_item_t block; config_item_t item; /* Get the config BLOCK */ if((block = config_FindItemByName(in_config, CONF_SNMP_ADM_LABEL)) == NULL) { /* cannot read item */ LogCrit(COMPONENT_CONFIG, "SNMP_ADM: Cannot read item \"%s\" from configuration file", CONF_SNMP_ADM_LABEL); /* Expected to be a block */ return ENOENT; } else if(config_ItemType(block) != CONFIG_ITEM_BLOCK) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: Cannot read item \"%s\" from configuration file", CONF_SNMP_ADM_LABEL); /* Expected to be a block */ return ENOENT; } /* makes an iteration on the (key, value) couplets */ var_max = config_GetNbItems(block); for(var_index = 0; var_index < var_max; var_index++) { /* retrieve key's name */ item = config_GetItemByIndex(block, var_index); err = config_GetKeyValue(item, &key_name, &key_value); if(err) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR reading key[%d] from section \"%s\" of configuration file.", var_index, CONF_LABEL_FS_SPECIFIC); return err; } /* what parameter is it ? */ if(!STRCMP(key_name, "Snmp_Agentx_Socket")) { if(strmaxcpy(out_parameter->snmp_adm.snmp_agentx_socket, key_value, sizeof(out_parameter->snmp_adm.snmp_agentx_socket)) == -1) LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: value \"%s\" for %s is too long", key_name, key_value); } else if(!STRCMP(key_name, "Product_Id")) { out_parameter->snmp_adm.product_id = atoi(key_value); } else if(!STRCMP(key_name, "Snmp_adm_log")) { if(strmaxcpy(out_parameter->snmp_adm.snmp_log_file, key_value, sizeof(out_parameter->snmp_adm.snmp_log_file)) == -1) LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: value \"%s\" for %s is too long", key_name, key_value); } else if(!STRCMP(key_name, "Export_cache_stats")) { int nbool = StrToBoolean(key_value); if(nbool == -1) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: Unexpected value for %s: boolean expected.", key_name); return EINVAL; } out_parameter->snmp_adm.export_cache_stats = nbool; } else if(!STRCMP(key_name, "Export_requests_stats")) { int nbool = StrToBoolean(key_value); if(nbool == -1) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: Unexpected value for %s: boolean expected.", key_name); return EINVAL; } out_parameter->snmp_adm.export_requests_stats = nbool; } else if(!STRCMP(key_name, "Export_maps_stats")) { int nbool = StrToBoolean(key_value); if(nbool == -1) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: Unexpected value for %s: boolean expected.", key_name); return EINVAL; } out_parameter->snmp_adm.export_maps_stats = nbool; } else if(!STRCMP(key_name, "Export_nfs_calls_detail")) { int nbool = StrToBoolean(key_value); if(nbool == -1) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: Unexpected value for %s: boolean expected.", key_name); return EINVAL; } out_parameter->snmp_adm.export_nfs_calls_detail = nbool; } else if(!STRCMP(key_name, "Export_FSAL_calls_detail")) { int nbool = StrToBoolean(key_value); if(nbool == -1) { LogCrit(COMPONENT_CONFIG, "SNMP_ADM: ERROR: Unexpected value for %s: boolean expected.", key_name); return EINVAL; } out_parameter->snmp_adm.export_fsal_calls_detail = nbool; } else { LogCrit(COMPONENT_CONFIG, "SNMP_ADM LOAD PARAMETER: ERROR: Unknown or unsettable key: %s (item %s)", key_name, CONF_LABEL_FS_SPECIFIC); return EINVAL; } } config_ok = 1; return 0; }
int nfs4_op_setclientid(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { SETCLIENTID4args * const arg_SETCLIENTID4 = &op->nfs_argop4_u.opsetclientid; SETCLIENTID4res * const res_SETCLIENTID4 = &resp->nfs_resop4_u.opsetclientid; clientaddr4 * const res_SETCLIENTID4_INUSE = &resp->nfs_resop4_u.opsetclientid.SETCLIENTID4res_u.client_using; char str_verifier[NFS4_VERIFIER_SIZE * 2 + 1]; struct display_buffer dspbuf_verifier = { sizeof(str_verifier), str_verifier, str_verifier}; char str_client[NFS4_OPAQUE_LIMIT * 2 + 1]; struct display_buffer dspbuf_client = { sizeof(str_client), str_client, str_client}; const char *str_client_addr = "(unknown)"; /* The clientid4 broken down into fields */ char str_clientid4[DISPLAY_CLIENTID_SIZE]; /* Display buffer for clientid4 */ struct display_buffer dspbuf_clientid4 = { sizeof(str_clientid4), str_clientid4, str_clientid4}; nfs_client_record_t *client_record; nfs_client_id_t *conf; nfs_client_id_t *unconf; clientid4 clientid; verifier4 verifier; int rc; resp->resop = NFS4_OP_SETCLIENTID; if (data->minorversion > 0) { res_SETCLIENTID4->status = NFS4ERR_NOTSUPP; return res_SETCLIENTID4->status; } if (op_ctx->client != NULL) str_client_addr = op_ctx->client->hostaddr_str; if (isDebug(COMPONENT_CLIENTID)) { display_opaque_value(&dspbuf_client, arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len); display_opaque_bytes(&dspbuf_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); } else { str_client[0] = '\0'; str_verifier[0] = '\0'; } LogDebug(COMPONENT_CLIENTID, "SETCLIENTID Client addr=%s id=%s verf=%s callback={program=%u r_addr=%s r_netid=%s} ident=%u", str_client_addr, str_client, str_verifier, arg_SETCLIENTID4->callback.cb_program, arg_SETCLIENTID4->callback.cb_location.r_addr, arg_SETCLIENTID4->callback.cb_location.r_netid, arg_SETCLIENTID4->callback_ident); /* Do we already have one or more records for client id (x)? */ client_record = get_client_record(arg_SETCLIENTID4->client.id.id_val, arg_SETCLIENTID4->client.id.id_len, 0, 0); if (client_record == NULL) { /* Some major failure */ LogCrit(COMPONENT_CLIENTID, "SETCLIENTID failed"); res_SETCLIENTID4->status = NFS4ERR_SERVERFAULT; return res_SETCLIENTID4->status; } /* The following checks are based on RFC3530bis draft 16 * * This attempts to implement the logic described in * 15.35.5. IMPLEMENTATION Consider the major bullets as CASE * 1, CASE 2, CASE 3, CASE 4, and CASE 5. */ PTHREAD_MUTEX_lock(&client_record->cr_mutex); if (isFullDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_record(&dspbuf, client_record); LogFullDebug(COMPONENT_CLIENTID, "Client Record %s cr_confirmed_rec=%p cr_unconfirmed_rec=%p", str, client_record->cr_confirmed_rec, client_record->cr_unconfirmed_rec); } conf = client_record->cr_confirmed_rec; if (conf != NULL) { bool credmatch; /* Need a reference to the confirmed record for below */ inc_client_id_ref(conf); clientid = conf->cid_clientid; display_clientid(&dspbuf_clientid4, clientid); credmatch = nfs_compare_clientcred(&conf->cid_credential, &data->credential) && op_ctx->client != NULL && conf->gsh_client != NULL && op_ctx->client == conf->gsh_client; /* Only reject if the principal doesn't match and the * clientid has live state associated. Per RFC 7530 * Section 9.1.2. Server Release of Client ID. */ if (!credmatch && clientid_has_state(conf)) { /* CASE 1: * * Confirmed record exists and not the same principal */ if (isDebug(COMPONENT_CLIENTID)) { char *confirmed_addr = "(unknown)"; if (conf->gsh_client != NULL) confirmed_addr = conf->gsh_client->hostaddr_str; LogDebug(COMPONENT_CLIENTID, "Confirmed ClientId %s->'%s': Principals do not match... confirmed addr=%s Return NFS4ERR_CLID_INUSE", str_clientid4, str_client, confirmed_addr); } res_SETCLIENTID4->status = NFS4ERR_CLID_INUSE; res_SETCLIENTID4_INUSE->r_netid = (char *)netid_nc_table[conf->cid_cb.v40.cb_addr.nc] .netid; res_SETCLIENTID4_INUSE->r_addr = gsh_strdup(conf->cid_cb.v40.cb_client_r_addr); /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); goto out; } /* Check if confirmed record is for (v, x, c, l, s) */ if (credmatch && memcmp(arg_SETCLIENTID4->client.verifier, conf->cid_incoming_verifier, NFS4_VERIFIER_SIZE) == 0) { /* CASE 2: * * A confirmed record exists for this long * form client id and verifier. * * Consider this to be a possible update of * the call-back information. * * Remove any pre-existing unconfirmed record * for (v, x, c). * * Return the same short form client id (c), * but a new setclientid_confirm verifier (t). */ LogFullDebug(COMPONENT_CLIENTID, "Update ClientId %s->%s", str_clientid4, str_client); new_clientid_verifier(verifier); } else { /* Must be CASE 3 or CASE 4 * * Confirmed record is for (u, x, c, l, s). * * These are actually the same, doesn't really * matter if an unconfirmed record exists or * not. Any existing unconfirmed record will * be removed and a new unconfirmed record * added. * * Return a new short form clientid (d) and a * new setclientid_confirm verifier (t). (Note * the spec calls the values e and r for CASE * 4). */ LogFullDebug(COMPONENT_CLIENTID, "Replace ClientId %s->%s", str_clientid4, str_client); clientid = new_clientid(); new_clientid_verifier(verifier); } /* Release our reference to the confirmed clientid. */ dec_client_id_ref(conf); } else { /* CASE 5: * * * Remove any existing unconfirmed record. * * Return a new short form clientid (d) and a new * setclientid_confirm verifier (t). */ clientid = new_clientid(); display_clientid(&dspbuf_clientid4, clientid); LogFullDebug(COMPONENT_CLIENTID, "New client %s", str_clientid4); new_clientid_verifier(verifier); } /* At this point, no matter what the case was above, we should * remove any pre-existing unconfirmed record. */ unconf = client_record->cr_unconfirmed_rec; if (unconf != NULL) { /* Delete the unconfirmed clientid record. Because we * have the cr_mutex, we have won any race to deal * with this clientid record (whether we raced with a * SETCLIENTID_CONFIRM or the reaper thread (if either * of those operations had won the race, * cr_punconfirmed_id would have been NULL). */ if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "Replacing %s", str); } /* unhash the clientid record */ remove_unconfirmed_client_id(unconf); unconf = NULL; } /* Now we can proceed to build the new unconfirmed record. We * have determined the clientid and setclientid_confirm values * above. */ unconf = create_client_id(clientid, client_record, &data->credential, 0); if (unconf == NULL) { /* Error already logged, return */ res_SETCLIENTID4->status = NFS4ERR_RESOURCE; goto out; } if (strmaxcpy(unconf->cid_cb.v40.cb_client_r_addr, arg_SETCLIENTID4->callback.cb_location.r_addr, sizeof(unconf->cid_cb.v40.cb_client_r_addr)) == -1) { LogCrit(COMPONENT_CLIENTID, "Callback r_addr %s too long", arg_SETCLIENTID4->callback.cb_location.r_addr); res_SETCLIENTID4->status = NFS4ERR_INVAL; goto out; } nfs_set_client_location(unconf, &arg_SETCLIENTID4->callback.cb_location); memcpy(unconf->cid_incoming_verifier, arg_SETCLIENTID4->client.verifier, NFS4_VERIFIER_SIZE); memcpy(unconf->cid_verifier, verifier, sizeof(NFS4_write_verifier)); unconf->cid_cb.v40.cb_program = arg_SETCLIENTID4->callback.cb_program; unconf->cid_cb.v40.cb_callback_ident = arg_SETCLIENTID4->callback_ident; rc = nfs_client_id_insert(unconf); if (rc != CLIENT_ID_SUCCESS) { /* Record is already freed, return. */ res_SETCLIENTID4->status = clientid_error_to_nfsstat_no_expire(rc); goto out; } if (isDebug(COMPONENT_CLIENTID)) { char str[LOG_BUFF_LEN] = "\0"; struct display_buffer dspbuf = {sizeof(str), str, str}; sprint_mem(str_verifier, verifier, NFS4_VERIFIER_SIZE); display_client_id_rec(&dspbuf, unconf); LogDebug(COMPONENT_CLIENTID, "SETCLIENTID reply Verifier=%s %s", str_verifier, str); } res_SETCLIENTID4->status = NFS4_OK; res_SETCLIENTID4->SETCLIENTID4res_u.resok4.clientid = clientid; memcpy(res_SETCLIENTID4->SETCLIENTID4res_u.resok4.setclientid_confirm, &verifier, NFS4_VERIFIER_SIZE); out: PTHREAD_MUTEX_unlock(&client_record->cr_mutex); /* Release our reference to the client record */ dec_client_record_ref(client_record); return res_SETCLIENTID4->status; }