#include <sys/types.h>
#include <rpc/rpc.h>
#include <netconfig.h>
#include <netdir.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libtsnet.h>
#include <nfs/nfssys.h>
#include <nfs/export.h>
#include <nfs/nfs_cmd.h>
#include <door.h>
#include <syslog.h>
#include <locale.h>
#include <strings.h>
#include <sharefs/share.h>
#include <stdlib.h>
#include "../lib/sharetab.h"
#include "mountd.h"
char *charopts[] = {
"euc-cn",
"euc-jp",
"euc-jpms",
"euc-kr",
"euc-tw",
"iso8859-1",
"iso8859-2",
"iso8859-5",
"iso8859-6",
"iso8859-7",
"iso8859-8",
"iso8859-9",
"iso8859-13",
"iso8859-15",
"koi8-r",
NULL
};
static void
nfscmd_err(door_desc_t *dp, nfscmd_arg_t *args, int err)
{
nfscmd_res_t res;
res.version = NFSCMD_VERS_1;
res.cmd = NFSCMD_ERROR;
res.error = err;
(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
(void) door_return(NULL, 0, NULL, 0);
}
static char *
charmap_search(struct netbuf *nbuf, char *opts)
{
char *copts;
char *next;
char *name;
char *result = NULL;
char *netid;
struct sockaddr *sa;
struct cln cln;
sa = (struct sockaddr *)nbuf->buf;
switch (sa->sa_family) {
case AF_INET:
netid = "tcp";
break;
case AF_INET6:
netid = "tcp6";
break;
default:
return (NULL);
}
copts = strdup(opts);
if (copts == NULL)
return (NULL);
cln_init_lazy(&cln, netid, nbuf);
next = copts;
while (*next != '\0') {
char *val;
name = next;
if (getsubopt(&next, charopts, &val) >= 0) {
char *cp;
cp = strchr(name, '=');
if (cp != NULL)
*cp = '\0';
if (in_access_list(&cln, val) > 0) {
result = name;
break;
}
}
}
if (result != NULL)
result = strdup(result);
cln_fini(&cln);
free(copts);
return (result);
}
static void
nfscmd_charmap_lookup(door_desc_t *dp, nfscmd_arg_t *args)
{
nfscmd_res_t res;
struct netbuf nb;
struct sockaddr sa;
struct share *sh = NULL;
char *name;
memset(&res, '\0', sizeof (res));
res.version = NFSCMD_VERS_1;
res.cmd = NFSCMD_CHARMAP_LOOKUP;
sh = findentry(args->arg.charmap.path);
if (sh != NULL) {
nb.len = nb.maxlen = sizeof (struct sockaddr);
nb.buf = (char *)&sa;
sa = args->arg.charmap.addr;
name = charmap_search(&nb, sh->sh_opts);
if (name != NULL) {
(void) strcpy(res.result.charmap.codeset, name);
res.result.charmap.apply = B_TRUE;
res.error = NFSCMD_ERR_SUCCESS;
free(name);
} else {
res.result.charmap.apply = B_FALSE;
res.error = NFSCMD_ERR_NOTFOUND;
}
sharefree(sh);
} else {
res.error = NFSCMD_ERR_NOTFOUND;
}
(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
(void) door_return(NULL, 0, NULL, 0);
}
static void
nfscmd_vers_1(door_desc_t *dp, nfscmd_arg_t *args, size_t size)
{
switch (args->cmd) {
case NFSCMD_CHARMAP_LOOKUP:
nfscmd_charmap_lookup(dp, args);
break;
default:
nfscmd_err(dp, args, NFSCMD_ERR_BADCMD);
break;
}
}
void
nfscmd_func(void *cookie, char *dataptr, size_t arg_size,
door_desc_t *dp, uint_t n_desc)
{
nfscmd_arg_t *args;
args = (nfscmd_arg_t *)dataptr;
switch (args->version) {
case NFSCMD_VERS_1:
nfscmd_vers_1(dp, args, arg_size);
break;
default:
syslog(LOG_ERR, gettext("Invalid nfscmd version"));
break;
}
(void) door_return((caddr_t)args, sizeof (nfscmd_res_t), NULL, 0);
(void) door_return(NULL, 0, NULL, 0);
}