/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <libscf.h>
#include <syslog.h>
#include <nfs/fedfs.h>
#include <libintl.h>
#include "fedfs_impl.h"
/*
* fedfs_smf_get_pg() - create a property group name based on host/port.
*
* On success, returns an allocated string with the name, which the
* caller must free. On failure, returns NULL.
*/
static char *
fedfs_smf_get_pg(char *host, int port)
{
int sz;
char *s, *buf;
char sport[10];
(void) snprintf(sport, sizeof (sport), "%d", port);
sz = strlen(host) + 1 + strlen(sport) + 1 + 5;
buf = calloc(sz, 1);
if (buf == NULL)
return (NULL);
(void) snprintf(buf, sz, "cred_%s_%s", host, sport);
for (s = buf; s < buf + sz; s++)
if (*s == '.' || *s == ',' || *s == '=')
*s = '_';
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_get_pg: built %s\n", buf);
#endif
return (buf);
}
/*
* fedfs_smf_lookup() - look up the distinguished name (user),
* password, NCE and security details for a particular host/port.
*
* On success, returns a pointer to an allocated nsdb_info_t structure
* which must be freed by the caller. On failure, returns NULL.
*/
nsdb_info_t *
fedfs_smf_lookup(char *host, int port, int prompt_pw)
{
char *p, *pgname;
scf_simple_prop_t *prop;
nsdb_info_t *info;
pgname = fedfs_smf_get_pg(host, port);
if (pgname == NULL)
return (NULL);
info = calloc(sizeof (nsdb_info_t), 1);
if (info == NULL) {
free(pgname);
return (NULL);
}
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, pgname, "binddn");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find binddn property in pg %s:%s\n",
pgname, scf_strerror(scf_error()));
free(info);
free(pgname);
return (NULL);
}
p = scf_simple_prop_next_astring(prop);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: binddn %s\n", p);
#endif
info->binddn = strdup(p);
scf_simple_prop_free(prop);
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, pgname, "bindpw");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find bindpw property in pg %s:%s\n",
pgname, scf_strerror(scf_error()));
fedfs_smf_lookup_free(info);
free(pgname);
return (NULL);
}
p = scf_simple_prop_next_astring(prop);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: bindpw %s\n", p);
#endif
if (strlen(p) != 0 && strcmp(p, "\"\"") != 0)
info->bindpw = strdup(p);
else if (prompt_pw) {
int len;
char *buf, *pw;
char *pstring = dgettext(TEXT_DOMAIN, "Enter password for %s:");
len = strlen(pstring) + strlen(info->binddn) + 1;
buf = malloc(len);
/* LINTED */
(void) snprintf(buf, len, pstring, info->binddn);
pw = getpassphrase(buf);
if (pw != NULL)
info->bindpw = strdup(pw);
else
info->bindpw = NULL;
free(buf);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: prompted pw %s\n",
info->bindpw);
#endif
} else
info->bindpw = NULL;
scf_simple_prop_free(prop);
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, pgname, "sectype");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find sectype property in pg %s:%s\n",
pgname, scf_strerror(scf_error()));
fedfs_smf_lookup_free(info);
free(pgname);
return (NULL);
}
p = scf_simple_prop_next_astring(prop);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: sectype %s\n", p);
#endif
if (strlen(p) != 0 && strcmp(p, "\"\"") != 0)
info->sectype = strdup(p);
else
info->sectype = NULL;
scf_simple_prop_free(prop);
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, pgname, "certpath");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find certpath property in pg %s:%s\n",
pgname, scf_strerror(scf_error()));
fedfs_smf_lookup_free(info);
free(pgname);
return (NULL);
}
p = scf_simple_prop_next_astring(prop);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: certpath %s\n", p);
#endif
if (strlen(p) != 0 && strcmp(p, "\"\"") != 0)
info->certpath = strdup(p);
else
info->certpath = NULL;
scf_simple_prop_free(prop);
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, pgname, "nce");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find nce property in pg %s:%s\n",
pgname, scf_strerror(scf_error()));
fedfs_smf_lookup_free(info);
free(pgname);
return (NULL);
}
p = scf_simple_prop_next_astring(prop);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_lookup: nce %s\n", p);
#endif
info->nce = strdup(p);
scf_simple_prop_free(prop);
free(pgname);
return (info);
}
void
fedfs_smf_lookup_free(nsdb_info_t *info)
{
if (info == NULL)
return;
free(info->binddn);
free(info->bindpw);
free(info->sectype);
free(info->certpath);
free(info->nce);
free(info);
}
/*
* get_pg_value() - from property group, get a named astring value.
*/
static char *
get_pg_value(scf_handle_t *h, scf_propertygroup_t *pg,
scf_property_t *prop, char *name)
{
size_t valsz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
char *valbuf;
scf_value_t *value = NULL;
if ((value = scf_value_create(h)) == NULL)
return (NULL);
if (scf_pg_get_property(pg, name, prop) == -1)
return (NULL);
if (scf_property_get_value(prop, value) == -1)
return (NULL);
valbuf = calloc(valsz, 1);
if (scf_value_get_astring(value, valbuf, valsz) == -1) {
free(valbuf);
return (NULL);
}
#ifdef DEBUG
fprintf(stderr, "get_pg_value: %s=%s\n", name, valbuf);
#endif
return (strdup(valbuf));
}
/*
* fedfs_smf_list() - enumerate all nsdbparams entried
*
* Returns the number of entries in the allocated array of nsdb_list_t
* entries to which the passed argument points on success. The array
* must be freed by the caller. On failure, the return is zero.
*/
int
fedfs_smf_list(nsdb_list_t **listp)
{
int num = 0;
scf_handle_t *h = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
scf_property_t *prop = NULL;
scf_iter_t *iter = NULL;
nsdb_list_t *list = NULL, *nlist;
size_t namesz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
char *namebuf;
size_t valsz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
char *valbuf;
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) != 0 ||
(svc = scf_service_create(h)) == NULL ||
(pg = scf_pg_create(h)) == NULL ||
(prop = scf_property_create(h)) == NULL ||
(iter = scf_iter_create(h)) == NULL ||
scf_handle_decode_fmri(h, FEDFS_CLIENT, NULL, svc,
NULL, NULL, NULL, 0) != 0) {
goto cleanup;
}
if (scf_iter_service_pgs_typed(iter, svc, SCF_GROUP_APPLICATION) != 0)
goto cleanup;
namebuf = calloc(namesz, 1);
if (namebuf == NULL)
goto cleanup;
valbuf = calloc(valsz, 1);
if (valbuf == NULL)
goto cleanup;
list = calloc(sizeof (nsdb_list_t), 1);
if (list == NULL)
goto cleanup;
for (;;) {
if (scf_iter_next_pg(iter, pg) != 1)
break;
if (scf_pg_get_name(pg, namebuf, namesz) == -1)
break;
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_list: found pg=%s\n", namebuf);
#endif
if (strncmp("cred_", namebuf, 5) != 0)
continue;
nlist = realloc(list, sizeof (nsdb_list_t) * ++num);
if (nlist == NULL) {
free(list);
list = NULL;
num = 0;
break;
}
list = nlist;
list[num - 1].hostname = get_pg_value(h, pg, prop, "hostname");
list[num - 1].portnum = get_pg_value(h, pg, prop, "port");
}
if (num > 0)
*listp = list;
else
free(list);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_list: found %d entries\n", num);
#endif
cleanup:
free(valbuf);
free(namebuf);
scf_iter_destroy(iter);
scf_pg_destroy(pg);
scf_service_destroy(svc);
if (h) {
(void) scf_handle_unbind(h);
scf_handle_destroy(h);
}
return (num);
}
/*
* fedfs_smf_delete() - delete the SMF property group entry for host/port.
*
* Returns 0 on success and -1 on failure, usually setting scf_error.
* A caller may print error diagnosis with scf_strerror().
*/
int
fedfs_smf_delete(char *host, int port)
{
char *pgname;
int err = -1;
scf_handle_t *h = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
pgname = fedfs_smf_get_pg(host, port);
if (pgname == NULL)
return (-1);
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) != 0 ||
(svc = scf_service_create(h)) == NULL ||
(pg = scf_pg_create(h)) == NULL ||
scf_handle_decode_fmri(h, FEDFS_CLIENT, NULL, svc,
NULL, NULL, NULL, 0) != 0 ||
scf_service_get_pg(svc, pgname, pg) != 0)
goto cleanup;
err = scf_pg_delete(pg);
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_delete: delete %s\n",
err == 0 ? "worked" : "failed");
#endif
cleanup:
if (err != 0)
syslog(LOG_WARNING,
"FedFS failed to delete pg %s:%s\n",
pgname, scf_strerror(scf_error()));
scf_pg_destroy(pg);
scf_service_destroy(svc);
if (h) {
(void) scf_handle_unbind(h);
scf_handle_destroy(h);
}
free(pgname);
return (err);
}
/*
* set_pg_value() - write a value out to SMF
*
* Returns 0 on success and -1 on failure, usually setting scf_error.
* A caller may print error diagnosis with scf_strerror().
*/
static int
set_pg_value(scf_handle_t *h, scf_propertygroup_t *pg,
char *propname, char *propvalue)
{
scf_transaction_t *tran = NULL;
scf_transaction_entry_t *entry = NULL;
scf_property_t *prop = NULL;
scf_value_t *value = NULL;
boolean_t new;
int ret = -1;
#ifdef DEBUG
fprintf(stderr, "set_pg_value: setting %s=%s\n", propname, propvalue);
#endif
do {
if ((tran = scf_transaction_create(h)) == NULL ||
(entry = scf_entry_create(h)) == NULL ||
(prop = scf_property_create(h)) == NULL ||
(value = scf_value_create(h)) == NULL)
return (-1);
new = (scf_pg_get_property(pg, propname, prop) != 0);
scf_property_destroy(prop);
if (scf_transaction_start(tran, pg) == -1)
goto cleanup;
if (new) {
if (scf_transaction_property_new(tran, entry,
propname, SCF_TYPE_ASTRING) == -1)
goto cleanup;
} else {
if (scf_transaction_property_change(tran, entry,
propname, SCF_TYPE_ASTRING) == -1)
goto cleanup;
}
if (scf_value_set_astring(value, propvalue) == -1 ||
scf_entry_add_value(entry, value) == -1)
goto cleanup;
ret = scf_transaction_commit(tran);
#ifdef DEBUG
fprintf(stderr, "set_pg_value: commit returned %d\n", ret);
#endif
if (ret == -1)
goto cleanup;
if (ret == 0) {
scf_transaction_reset(tran);
scf_entry_reset(entry);
if (scf_pg_update(pg) == -1)
goto cleanup;
}
} while (ret == 0);
if (ret == 1)
ret = 0;
cleanup:
scf_value_destroy(value);
scf_entry_destroy(entry);
scf_transaction_destroy(tran);
return (ret);
}
/*
* fedfs_smf_update() - update or create the SMF property group entry for
* host/port.
*
* Returns 0 on success and -1 on failure, while also setting scf_error.
* A caller may print error diagnosis with scf_strerror().
*/
int
fedfs_smf_update(char *host, int port, nsdb_info_t *info)
{
char *pgname, sport[10];
int err = -1;
scf_handle_t *h = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
scf_iter_t *iter = NULL;
pgname = fedfs_smf_get_pg(host, port);
if (pgname == NULL)
return (-1);
(void) snprintf(sport, sizeof (sport), "%d", port);
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) != 0 ||
(svc = scf_service_create(h)) == NULL ||
(pg = scf_pg_create(h)) == NULL ||
(iter = scf_iter_create(h)) == NULL ||
scf_handle_decode_fmri(h, FEDFS_CLIENT, NULL, svc,
NULL, NULL, NULL, 0) != 0)
goto cleanup;
if (scf_service_get_pg(svc, pgname, pg) != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_update: pg not found\n");
#endif
if (scf_error() != SCF_ERROR_NOT_FOUND) {
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_update: for a bad reason\n");
#endif
goto cleanup;
}
if (scf_service_add_pg(svc, pgname, SCF_GROUP_APPLICATION,
0, pg) != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_update: can't be created\n");
#endif
goto cleanup;
}
}
if (info->bindpw == NULL)
info->bindpw = "";
if (info->sectype == NULL)
info->sectype = "";
if (info->certpath == NULL)
info->certpath = "";
if (set_pg_value(h, pg, "hostname", host) != 0 ||
set_pg_value(h, pg, "port", sport) != 0 ||
set_pg_value(h, pg, "nce", info->nce) != 0 ||
set_pg_value(h, pg, "binddn", info->binddn) != 0 ||
set_pg_value(h, pg, "bindpw", info->bindpw) != 0 ||
set_pg_value(h, pg, "sectype", info->sectype) != 0 ||
set_pg_value(h, pg, "certpath", info->certpath) != 0 ||
set_pg_value(h, pg, "read_authorization",
"solaris.smf.read.fedfs") != 0 ||
set_pg_value(h, pg, "value_authorization",
"solaris.smf.value.fedfs") != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_smf_update: can't be saved\n");
#endif
err = 1;
} else
err = 0;
(void) smf_refresh_instance(FEDFS_CLIENT);
cleanup:
if (err != 0)
syslog(LOG_WARNING,
"FedFS failed to add property to pg %s:%s\n",
pgname, scf_strerror(scf_error()));
scf_iter_destroy(iter);
scf_pg_destroy(pg);
scf_service_destroy(svc);
if (h) {
(void) scf_handle_unbind(h);
scf_handle_destroy(h);
}
free(pgname);
return (err);
}
/*
* fedfs_get_default_host() - get a default host value from env or SMF.
*
* On success, returns an allocated string with the name, which the
* caller must free. On failure, returns NULL.
*/
char *
fedfs_get_default_host()
{
char *v = NULL;
scf_simple_prop_t *prop = NULL;
v = getenv("FEDFS_NSDB_HOST");
if (v != NULL) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_host: host %s (env)\n", v);
#endif
v = strdup(v);
goto out;
}
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, "default", "hostname");
if (!prop)
goto out;
v = scf_simple_prop_next_astring(prop);
if (v != NULL) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_host: host %s (SMF)\n", v);
#endif
v = strdup(v);
}
out:
if (v == NULL || strlen(v) == 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_host: host %s (def)\n", v);
#endif
free(v);
v = strdup("localhost");
}
scf_simple_prop_free(prop);
return (v);
}
/*
* fedfs_get_default_port() - get a default port value from env or SMF.
*
* On success, returns an allocated string with the name, which the
* caller must free. On failure, returns NULL.
*/
char *
fedfs_get_default_port()
{
char *v = NULL;
scf_simple_prop_t *prop = NULL;
v = getenv("FEDFS_NSDB_PORT");
if (v != NULL) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_port: port %s (env)\n", v);
#endif
v = strdup(v);
goto out;
}
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, "default", "port");
if (!prop)
goto out;
v = scf_simple_prop_next_astring(prop);
if (v != NULL && strcmp(v, "\"\"") != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_port: port %s (SMF)\n", v);
#endif
v = strdup(v);
}
out:
if (v == NULL || strlen(v) == 0 || strcmp(v, "\"\"") == 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_get_default_port: port %s (def)\n", v);
#endif
free(v);
v = strdup("389");
}
scf_simple_prop_free(prop);
return (v);
}
/*
* fedfs_use_loopback() - query SMF "force_loopback" property
*
* Returns:
* -1: inconclusive (likely no such property or FMRI)
* 0: force_loopback is false
* 1: force_loopback is true
*/
int
fedfs_use_loopback()
{
scf_simple_prop_t *prop = NULL;
int retval = -1;
uint8_t *ret;
prop = scf_simple_prop_get(NULL, FEDFS_CLIENT, "default",
"force_loopback");
if (!prop) {
syslog(LOG_WARNING,
"FedFS failed to find force_loopback property:%s\n",
scf_strerror(scf_error()));
return (retval);
}
ret = scf_simple_prop_next_boolean(prop);
retval = (*ret != 0);
scf_simple_prop_free(prop);
return (retval);
}
/*
* fedfs_set_default() - update the SMF default property; properties
* are hostname and port.
*
* Returns 0 on success and -1 on failure, while also setting scf_error.
* A caller may print error diagnosis with scf_strerror().
*/
int
fedfs_set_default(char *prop, char *value)
{
int err = -1;
scf_handle_t *h = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) != 0 ||
(svc = scf_service_create(h)) == NULL ||
(pg = scf_pg_create(h)) == NULL ||
scf_handle_decode_fmri(h, FEDFS_CLIENT, NULL, svc,
NULL, NULL, NULL, 0) != 0)
goto cleanup;
if (scf_service_get_pg(svc, "default", pg) != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_default: pg not found\n");
#endif
goto cleanup;
}
#ifdef DEBUG
fprintf(stderr, "fedfs_set_default: setting %s=%s\n", prop, value);
#endif
err = 0;
if (strncmp(prop, "hostname", 8) == 0)
err = set_pg_value(h, pg, "hostname", value);
if (strncmp(prop, "port", 4) == 0)
err = set_pg_value(h, pg, "port", value);
#ifdef DEBUG
if (err < 0)
fprintf(stderr, "fedfs_set_default: can't be saved\n");
#endif
(void) smf_refresh_instance(FEDFS_CLIENT);
cleanup:
scf_pg_destroy(pg);
scf_service_destroy(svc);
if (h) {
(void) scf_handle_unbind(h);
scf_handle_destroy(h);
}
if (err != 0)
syslog(LOG_WARNING,
"FedFS failed to update default pg: %s\n",
scf_strerror(scf_error()));
return (err);
}
/*
* fedfs_set_loopback() - update the SMF default/force_loopback property
*
* Returns 0 on success and -1 on failure, while also setting scf_error.
* A caller may print error diagnosis with scf_strerror().
*/
int
fedfs_set_loopback(boolean_t setting)
{
int ret = -1;
scf_handle_t *h = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
scf_transaction_t *tran = NULL;
scf_transaction_entry_t *entry = NULL;
scf_value_t *value = NULL;
if ((h = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(h) != 0 ||
(svc = scf_service_create(h)) == NULL ||
(pg = scf_pg_create(h)) == NULL ||
scf_handle_decode_fmri(h, FEDFS_CLIENT, NULL, svc,
NULL, NULL, NULL, 0) != 0)
goto cleanup;
if (scf_service_get_pg(svc, "default", pg) != 0) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: pg not found\n");
#endif
goto cleanup;
}
do {
if ((tran = scf_transaction_create(h)) == NULL ||
(entry = scf_entry_create(h)) == NULL ||
(value = scf_value_create(h)) == NULL) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: no trans\n");
#endif
goto cleanup;
}
if (scf_transaction_start(tran, pg) == -1) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: no start\n");
#endif
goto cleanup;
}
if (scf_transaction_property_change(tran, entry,
"force_loopback", SCF_TYPE_BOOLEAN) == -1) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: no change\n");
#endif
goto cleanup;
}
scf_value_set_boolean(value, setting);
if (scf_entry_add_value(entry, value) == -1) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: no value\n");
#endif
goto cleanup;
}
ret = scf_transaction_commit(tran);
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: commit said %d\n", ret);
#endif
if (ret == -1)
goto cleanup;
if (ret == 0) {
scf_transaction_reset(tran);
scf_entry_reset(entry);
if (scf_pg_update(pg) == -1) {
#ifdef DEBUG
fprintf(stderr, "fedfs_set_loopback: update\n");
#endif
ret = -1;
goto cleanup;
}
}
} while (ret == 0);
if (ret == 1)
ret = 0;
cleanup:
if (ret != 0)
syslog(LOG_WARNING,
"FedFS failed to write force_loopback property:%s\n",
scf_strerror(scf_error()));
scf_pg_destroy(pg);
scf_service_destroy(svc);
if (h) {
(void) scf_handle_unbind(h);
scf_handle_destroy(h);
}
return (ret);
}
int
sectype_to_int(char *sectype)
{
if (strcmp(sectype, "FEDFS_SEC_TLS") == 0)
return (FEDFS_SEC_TLS);
else if (strcmp(sectype, "FEDFS_SEC_NONE") == 0)
return (FEDFS_SEC_NONE);
else
return (-1);
}