Merge pull request #15 from Oichkatzelesfrettschen/eirikr/remove-netbsd-references-and-files
This commit is contained in:
commit
1d9b0755f7
|
|
@ -1,32 +0,0 @@
|
|||
# $NetBSD: Makefile,v 1.25 2012/03/21 05:37:43 matt Exp $
|
||||
#
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
USE_FORT?= yes # data-driven bugs?
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
LIB= puffs
|
||||
|
||||
SRCS= puffs.c callcontext.c creds.c \
|
||||
paths.c pnode.c \
|
||||
subr.c
|
||||
MAN= puffs.3 puffs_cc.3 puffs_cred.3 puffs_flush.3 \
|
||||
puffs_framebuf.3 puffs_node.3 puffs_ops.3 puffs_path.3
|
||||
INCS= puffs.h
|
||||
INCSDIR= /usr/include
|
||||
LINTFLAGS+=-S -w
|
||||
|
||||
.if defined(__MINIX)
|
||||
.PATH: ${NETBSDSRCDIR}/minix/lib/libpuffs
|
||||
SRCS+= inode.c link.c main.c misc.c mount.c open.c path.c \
|
||||
protect.c read.c stadir.c time.c utility.c \
|
||||
table.c
|
||||
|
||||
CPPFLAGS+= -D_MINIX_SYSTEM -I${.CURDIR} -I${NETBSDSRCDIR}/minix/lib/libpuffs
|
||||
|
||||
NOGCCERROR=yes
|
||||
.endif # defined(__MINIX)
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
$NetBSD: TODO,v 1.3 2007/07/19 07:48:10 pooka Exp $
|
||||
|
||||
Document some possible user-visible changes that may take place.
|
||||
For a complete list, please dump my brain and excavate.
|
||||
|
||||
* figure out what do to with struct vattr, maybe introduce some
|
||||
vattr-like puffs-specific structure (translation costs?) instead
|
||||
of direct exposure
|
||||
|
||||
* make puffs_node opaque outside the library
|
||||
|
||||
* make it possible to cache symlink names and getattr results in
|
||||
the kernel ... although I'm not as critically concerned with the
|
||||
kernel caching as I am with userlevel caching
|
||||
|
||||
* try to implement a kernel policy for VOP_ACCESS, it's called
|
||||
very very often - but this requires some kernel caching
|
||||
|
||||
+ also try to figure out how to implement it in cases where it's
|
||||
more difficult to do, e.g. how can we know readdir on sshfs will
|
||||
fail without actually trying to read the directory? If we fail
|
||||
readdir itself, it's treated as success
|
||||
|
||||
* implement file system layering .. this will most likely bring
|
||||
massive changes to how the ops vector is handled, for instance.
|
||||
pcc/pu division should stay quite like the way it is now, but
|
||||
maybe there will be layer specific ops.
|
||||
|
||||
* make puffs more like kernel vfs - or make kernel vfs more like puffs
|
||||
|
||||
* decide what to do about setback operations. they kind of violate
|
||||
the transparency of FAF for op handling
|
||||
|
||||
* remove flags parameter to puffs_init and replace with something
|
||||
more generic
|
||||
|
||||
* fix incoming requests to not require memcpy with continuations
|
||||
(not user-visible?)
|
||||
|
||||
* make continuations play with libpthread, lib/36011 (not user-visible?)
|
||||
|
||||
* clean up the request dispatching / continuation code (not user-visible?)
|
||||
|
|
@ -1,372 +0,0 @@
|
|||
/* $NetBSD: callcontext.c,v 1.27 2011/12/06 21:15:39 skrll Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Research Foundation of Helsinki University of Technology
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: callcontext.c,v 1.27 2011/12/06 21:15:39 skrll Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ucontext.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
#if 0
|
||||
#define DPRINTF(x) printf x
|
||||
#else
|
||||
#define DPRINTF(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the following to 1 to not handle each request on a separate
|
||||
* stack. This is highly volatile kludge, therefore no external
|
||||
* interface.
|
||||
*/
|
||||
int puffs_fakecc;
|
||||
|
||||
/*
|
||||
* user stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
* So, we need to get back to where we came from. This can happen in two
|
||||
* different ways:
|
||||
* 1) PCC_MLCONT is set, in which case we need to go to the mainloop
|
||||
* 2) It is not set, and we simply jump to pcc_uc_ret.
|
||||
*/
|
||||
void
|
||||
puffs_cc_yield(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_cc *jumpcc;
|
||||
int rv;
|
||||
|
||||
assert(puffs_fakecc == 0);
|
||||
|
||||
if ((~pcc->pcc_flags & (PCC_BORROWED|PCC_DONE)) == 0) {
|
||||
pcc->pcc_flags &= ~(PCC_BORROWED|PCC_DONE);
|
||||
/*
|
||||
* see the XXX comment in puffs__cc_cont
|
||||
*/
|
||||
puffs__cc_destroy(pcc, 1);
|
||||
setcontext(&pcc->pcc_uc_ret);
|
||||
}
|
||||
pcc->pcc_flags &= ~PCC_BORROWED;
|
||||
|
||||
/* romanes eunt domus */
|
||||
DPRINTF(("puffs_cc_yield: "));
|
||||
if ((pcc->pcc_flags & PCC_MLCONT) == 0) {
|
||||
DPRINTF(("no mlcont, pcc %p\n", pcc));
|
||||
swapcontext(&pcc->pcc_uc, &pcc->pcc_uc_ret);
|
||||
} else {
|
||||
DPRINTF(("mlcont, pcc %p\n", pcc));
|
||||
pcc->pcc_flags &= ~PCC_MLCONT;
|
||||
rv = puffs__cc_create(pcc->pcc_pu, puffs__theloop, &jumpcc);
|
||||
if (rv)
|
||||
abort(); /* p-p-p-pa-pa-panic (XXX: fixme) */
|
||||
swapcontext(&pcc->pcc_uc, &jumpcc->pcc_uc);
|
||||
DPRINTF(("puffs_cc_yield: post swap pcc %p\n", pcc));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal continue routine. This has slightly different semantics.
|
||||
* We simply make our cc available in the freelist and jump to the
|
||||
* indicated pcc.
|
||||
*/
|
||||
void
|
||||
puffs__cc_cont(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_cc *mycc;
|
||||
|
||||
mycc = puffs_cc_getcc(pcc->pcc_pu);
|
||||
DPRINTF(("puffs__cc_cont: pcc %p, mycc %p\n", pcc, mycc));
|
||||
|
||||
/*
|
||||
* XXX: race between setcontext() and recycle if
|
||||
* we go multithreaded
|
||||
*/
|
||||
puffs__cc_destroy(mycc, 1);
|
||||
pcc->pcc_flags |= PCC_MLCONT;
|
||||
setcontext(&pcc->pcc_uc);
|
||||
}
|
||||
|
||||
void
|
||||
puffs_cc_continue(struct puffs_cc *pcc)
|
||||
{
|
||||
|
||||
/* ramble on */
|
||||
DPRINTF(("puffs_cc_continue: pcc %p\n", pcc));
|
||||
if (puffs_fakecc) {
|
||||
pcc->pcc_func(pcc->pcc_farg);
|
||||
} else {
|
||||
swapcontext(&pcc->pcc_uc_ret, &pcc->pcc_uc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "Borrows" pcc, *NOT* called from pcc owner. Acts like continue.
|
||||
* So the idea is to use this, give something the context back to
|
||||
* run to completion and then jump back to where ever this was called
|
||||
* from after the op dispatching is complete (or if the pcc decides to
|
||||
* yield again).
|
||||
*/
|
||||
void
|
||||
puffs__goto(struct puffs_cc *loanpcc)
|
||||
{
|
||||
|
||||
loanpcc->pcc_flags |= PCC_BORROWED;
|
||||
|
||||
swapcontext(&loanpcc->pcc_uc_ret, &loanpcc->pcc_uc);
|
||||
}
|
||||
|
||||
void
|
||||
puffs_cc_schedule(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
|
||||
assert(pu->pu_state & PU_INLOOP);
|
||||
TAILQ_INSERT_TAIL(&pu->pu_sched, pcc, pcc_schedent);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_cc_getcaller(struct puffs_cc *pcc, pid_t *pid, lwpid_t *lid)
|
||||
{
|
||||
|
||||
if ((pcc->pcc_flags & PCC_HASCALLER) == 0) {
|
||||
errno = ESRCH;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid)
|
||||
*pid = pcc->pcc_pid;
|
||||
if (lid)
|
||||
*lid = pcc->pcc_lid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct puffs_cc fakecc;
|
||||
|
||||
static struct puffs_cc *
|
||||
slowccalloc(struct puffs_usermount *pu)
|
||||
{
|
||||
struct puffs_cc *volatile pcc;
|
||||
void *sp;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
#if !defined(__minix)
|
||||
const long psize = sysconf(_SC_PAGESIZE);
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
if (puffs_fakecc)
|
||||
return &fakecc;
|
||||
|
||||
sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
|
||||
MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), -1, 0);
|
||||
if (sp == MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
pcc = sp;
|
||||
memset(pcc, 0, sizeof(struct puffs_cc));
|
||||
|
||||
#if !defined(__minix)
|
||||
#ifndef __MACHINE_STACK_GROWS_UP
|
||||
mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
|
||||
#else
|
||||
mprotect((uint8_t *)sp + stacksize - psize, (size_t)psize, PROT_NONE);
|
||||
#endif
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
/* initialize both ucontext's */
|
||||
if (getcontext(&pcc->pcc_uc) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return NULL;
|
||||
}
|
||||
if (getcontext(&pcc->pcc_uc_ret) == -1) {
|
||||
munmap(pcc, stacksize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pcc;
|
||||
}
|
||||
|
||||
int
|
||||
puffs__cc_create(struct puffs_usermount *pu, puffs_ccfunc func,
|
||||
struct puffs_cc **pccp)
|
||||
{
|
||||
struct puffs_cc *pcc;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
stack_t *st;
|
||||
|
||||
/* Do we have a cached copy? */
|
||||
if (pu->pu_cc_nstored == 0) {
|
||||
pcc = slowccalloc(pu);
|
||||
if (pcc == NULL)
|
||||
return -1;
|
||||
pcc->pcc_pu = pu;
|
||||
DPRINTF(("puffs__cc_create: allocated pcc %p\n", pcc));
|
||||
} else {
|
||||
pcc = LIST_FIRST(&pu->pu_ccmagazin);
|
||||
assert(pcc != NULL);
|
||||
|
||||
LIST_REMOVE(pcc, pcc_rope);
|
||||
pu->pu_cc_nstored--;
|
||||
DPRINTF(("puffs__cc_create: magazin pcc %p\n", pcc));
|
||||
}
|
||||
assert(pcc->pcc_pu == pu);
|
||||
|
||||
if (puffs_fakecc) {
|
||||
pcc->pcc_func = func;
|
||||
pcc->pcc_farg = pcc;
|
||||
} else {
|
||||
const long psize = sysconf(_SC_PAGESIZE);
|
||||
|
||||
/* link context */
|
||||
pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
|
||||
|
||||
/* setup stack
|
||||
*
|
||||
* XXX: I guess this should theoretically be preserved by
|
||||
* swapcontext(). However, it gets lost. So reinit it.
|
||||
*/
|
||||
st = &pcc->pcc_uc.uc_stack;
|
||||
st->ss_sp = ((uint8_t *)(void *)pcc) + psize;
|
||||
st->ss_size = stacksize - psize;
|
||||
st->ss_flags = 0;
|
||||
|
||||
/*
|
||||
* Give us an initial context to jump to.
|
||||
*
|
||||
* Our manual page says that portable code shouldn't
|
||||
* rely on being able to pass pointers through makecontext().
|
||||
* kjk says that NetBSD code doesn't need to worry about this.
|
||||
* uwe says it would be like putting a "keep away from
|
||||
* children" sign on a box of toys.
|
||||
*/
|
||||
makecontext(&pcc->pcc_uc, (void *)func, 1, (uintptr_t)pcc);
|
||||
}
|
||||
|
||||
*pccp = pcc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
puffs__cc_setcaller(struct puffs_cc *pcc, pid_t pid, lwpid_t lid)
|
||||
{
|
||||
|
||||
pcc->pcc_pid = pid;
|
||||
pcc->pcc_lid = lid;
|
||||
pcc->pcc_flags |= PCC_HASCALLER;
|
||||
}
|
||||
|
||||
static void
|
||||
cc_free(struct puffs_cc *pcc)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
|
||||
DPRINTF(("invalidating pcc %p\n", pcc));
|
||||
assert(!puffs_fakecc);
|
||||
munmap(pcc, stacksize);
|
||||
}
|
||||
|
||||
void
|
||||
puffs__cc_destroy(struct puffs_cc *pcc, int nonuke)
|
||||
{
|
||||
struct puffs_usermount *pu = pcc->pcc_pu;
|
||||
|
||||
pcc->pcc_flags &= ~PCC_HASCALLER;
|
||||
assert(pcc->pcc_flags == 0);
|
||||
assert(!puffs_fakecc);
|
||||
|
||||
/* not over limit? stuff away in the store, otherwise nuke */
|
||||
if (nonuke || pu->pu_cc_nstored < PUFFS_CCMAXSTORE) {
|
||||
pcc->pcc_pb = NULL;
|
||||
DPRINTF(("puffs__cc_destroy: storing pcc %p\n", pcc));
|
||||
LIST_INSERT_HEAD(&pu->pu_ccmagazin, pcc, pcc_rope);
|
||||
pu->pu_cc_nstored++;
|
||||
} else {
|
||||
cc_free(pcc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
puffs__cc_exit(struct puffs_usermount *pu)
|
||||
{
|
||||
struct puffs_cc *pcc;
|
||||
|
||||
while ((pcc = LIST_FIRST(&pu->pu_ccmagazin)) != NULL) {
|
||||
LIST_REMOVE(pcc, pcc_rope);
|
||||
cc_free(pcc);
|
||||
}
|
||||
}
|
||||
|
||||
struct puffs_cc *
|
||||
puffs_cc_getcc(struct puffs_usermount *pu)
|
||||
{
|
||||
size_t stacksize = 1<<pu->pu_cc_stackshift;
|
||||
uintptr_t bottom;
|
||||
|
||||
if (puffs_fakecc)
|
||||
return &fakecc;
|
||||
|
||||
bottom = ((uintptr_t)&bottom) & ~(stacksize-1);
|
||||
return (struct puffs_cc *)bottom;
|
||||
}
|
||||
|
||||
int
|
||||
puffs__cc_savemain(struct puffs_usermount *pu)
|
||||
{
|
||||
|
||||
if (puffs_fakecc)
|
||||
return 0;
|
||||
|
||||
PU_CLRSFLAG(pu, PU_MAINRESTORE);
|
||||
return getcontext(&pu->pu_mainctx);
|
||||
}
|
||||
|
||||
int
|
||||
puffs__cc_restoremain(struct puffs_usermount *pu)
|
||||
{
|
||||
|
||||
if (puffs_fakecc)
|
||||
return 0;
|
||||
|
||||
puffs__cc_destroy(puffs_cc_getcc(pu), 1);
|
||||
PU_SETSFLAG(pu, PU_MAINRESTORE);
|
||||
return setcontext(&pu->pu_mainctx);
|
||||
}
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
/* $NetBSD: creds.c,v 1.16 2012/03/15 12:49:36 njoly Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the Ulla Tuominen Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: creds.c,v 1.16 2012/03/15 12:49:36 njoly Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
/*
|
||||
* Interface for dealing with credits.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
#define UUCCRED(a) (a->pkcr_type == PUFFCRED_TYPE_UUC)
|
||||
#define INTCRED(a) (a->pkcr_type == PUFFCRED_TYPE_INTERNAL)
|
||||
|
||||
int
|
||||
puffs_cred_getuid(const struct puffs_cred *pcr, uid_t *ruid)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
if (!UUCCRED(pkcr)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
*ruid = pkcr->pkcr_uuc.cr_uid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_cred_getgid(const struct puffs_cred *pcr, gid_t *rgid)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
if (!UUCCRED(pkcr)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
*rgid = pkcr->pkcr_uuc.cr_gid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_cred_getgroups(const struct puffs_cred *pcr, gid_t *rgids, short *ngids)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
size_t ncopy;
|
||||
|
||||
if (!UUCCRED(pkcr)) {
|
||||
errno = EOPNOTSUPP;
|
||||
*ngids = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ncopy = MIN(*ngids, pkcr->pkcr_uuc.cr_ngroups);
|
||||
(void)memcpy(rgids, pkcr->pkcr_uuc.cr_groups, sizeof(gid_t) * ncopy);
|
||||
*ngids = (short)ncopy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_isuid(const struct puffs_cred *pcr, uid_t uid)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
return UUCCRED(pkcr) && pkcr->pkcr_uuc.cr_uid == uid;
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_hasgroup(const struct puffs_cred *pcr, gid_t gid)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
short i;
|
||||
|
||||
if (!UUCCRED(pkcr))
|
||||
return false;
|
||||
|
||||
if (pkcr->pkcr_uuc.cr_gid == gid)
|
||||
return true;
|
||||
for (i = 0; i < pkcr->pkcr_uuc.cr_ngroups; i++)
|
||||
if (pkcr->pkcr_uuc.cr_groups[i] == gid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_isregular(const struct puffs_cred *pcr)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
return UUCCRED(pkcr);
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_iskernel(const struct puffs_cred *pcr)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
return INTCRED(pkcr) && pkcr->pkcr_internal == PUFFCRED_CRED_NOCRED;
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_isfs(const struct puffs_cred *pcr)
|
||||
{
|
||||
PUFFS_MAKEKCRED(pkcr, pcr);
|
||||
|
||||
return INTCRED(pkcr) && pkcr->pkcr_internal == PUFFCRED_CRED_FSCRED;
|
||||
}
|
||||
|
||||
bool
|
||||
puffs_cred_isjuggernaut(const struct puffs_cred *pcr)
|
||||
{
|
||||
|
||||
return puffs_cred_isuid(pcr, 0) || puffs_cred_iskernel(pcr)
|
||||
|| puffs_cred_isfs(pcr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic routine for checking file access rights. Modeled after
|
||||
* vaccess() in the kernel.
|
||||
*/
|
||||
int
|
||||
puffs_access(enum vtype type, mode_t file_mode, uid_t uid, gid_t gid,
|
||||
mode_t acc_mode, const struct puffs_cred *pcr)
|
||||
{
|
||||
mode_t mask;
|
||||
|
||||
/* megapower */
|
||||
if (puffs_cred_iskernel(pcr) || puffs_cred_isfs(pcr))
|
||||
return 0;
|
||||
|
||||
/* superuser, allow all except exec if *ALL* exec bits are unset */
|
||||
if (puffs_cred_isuid(pcr, 0)) {
|
||||
if ((acc_mode & PUFFS_VEXEC) && type != VDIR &&
|
||||
(file_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
|
||||
return EACCES;
|
||||
return 0;
|
||||
}
|
||||
|
||||
mask = 0;
|
||||
/* owner */
|
||||
if (puffs_cred_isuid(pcr, uid)) {
|
||||
if (acc_mode & PUFFS_VEXEC)
|
||||
mask |= S_IXUSR;
|
||||
if (acc_mode & PUFFS_VREAD)
|
||||
mask |= S_IRUSR;
|
||||
if (acc_mode & PUFFS_VWRITE)
|
||||
mask |= S_IWUSR;
|
||||
/* group */
|
||||
} else if (puffs_cred_hasgroup(pcr, gid)) {
|
||||
if (acc_mode & PUFFS_VEXEC)
|
||||
mask |= S_IXGRP;
|
||||
if (acc_mode & PUFFS_VREAD)
|
||||
mask |= S_IRGRP;
|
||||
if (acc_mode & PUFFS_VWRITE)
|
||||
mask |= S_IWGRP;
|
||||
/* other */
|
||||
} else {
|
||||
if (acc_mode & PUFFS_VEXEC)
|
||||
mask |= S_IXOTH;
|
||||
if (acc_mode & PUFFS_VREAD)
|
||||
mask |= S_IROTH;
|
||||
if (acc_mode & PUFFS_VWRITE)
|
||||
mask |= S_IWOTH;
|
||||
}
|
||||
|
||||
if ((file_mode & mask) == mask)
|
||||
return 0;
|
||||
else
|
||||
return EACCES;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_access_chown(uid_t owner, gid_t group, uid_t newowner, gid_t newgroup,
|
||||
const struct puffs_cred *pcr)
|
||||
{
|
||||
|
||||
if (newowner == (uid_t)PUFFS_VNOVAL)
|
||||
newowner = owner;
|
||||
if (newgroup == (gid_t)PUFFS_VNOVAL)
|
||||
newgroup = group;
|
||||
|
||||
if ((!puffs_cred_isuid(pcr, owner) || newowner != owner ||
|
||||
((newgroup != group && !puffs_cred_hasgroup(pcr, newgroup))))
|
||||
&& !puffs_cred_isjuggernaut(pcr))
|
||||
return EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_access_chmod(uid_t owner, gid_t group, enum vtype type, mode_t mode,
|
||||
const struct puffs_cred *pcr)
|
||||
{
|
||||
|
||||
if (!puffs_cred_isuid(pcr, owner) && !puffs_cred_isjuggernaut(pcr))
|
||||
return EPERM;
|
||||
|
||||
if (!puffs_cred_isjuggernaut(pcr)) {
|
||||
if (type != VDIR && (mode & S_ISTXT))
|
||||
return EFTYPE;
|
||||
if (!puffs_cred_hasgroup(pcr, group) && (mode & S_ISGID))
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_access_times(uid_t uid, gid_t gid, mode_t mode, int va_utimes_null,
|
||||
const struct puffs_cred *pcr)
|
||||
{
|
||||
|
||||
if (puffs_cred_isuid(pcr, uid) || puffs_cred_isjuggernaut(pcr))
|
||||
return 0;
|
||||
|
||||
if (va_utimes_null == 0)
|
||||
return EPERM;
|
||||
|
||||
return puffs_access(VNON, mode, uid, gid, PUFFS_VWRITE, pcr);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,135 +0,0 @@
|
|||
/* $NetBSD: flush.c,v 1.16 2008/08/12 19:44:39 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: flush.c,v 1.16 2008/08/12 19:44:39 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
/*
|
||||
* Flushing / invalidation routines
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
#if 0
|
||||
int
|
||||
puffs_inval_namecache_node(struct puffs_usermount *pu, puffs_cookie_t cookie,
|
||||
const char *name)
|
||||
{
|
||||
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
doflush(struct puffs_usermount *pu, puffs_cookie_t cookie, int op,
|
||||
off_t start, off_t end)
|
||||
{
|
||||
struct puffs_framebuf *pb;
|
||||
struct puffs_flush *pf;
|
||||
size_t winlen;
|
||||
int rv;
|
||||
|
||||
pb = puffs_framebuf_make();
|
||||
if (pb == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
winlen = sizeof(struct puffs_flush);
|
||||
if ((rv = puffs_framebuf_getwindow(pb, 0, (void *)&pf, &winlen)) == -1)
|
||||
goto out;
|
||||
assert(winlen == sizeof(struct puffs_flush));
|
||||
|
||||
pf->pf_req.preq_buflen = sizeof(struct puffs_flush);
|
||||
pf->pf_req.preq_opclass = PUFFSOP_FLUSH;
|
||||
pf->pf_req.preq_id = puffs__nextreq(pu);
|
||||
|
||||
pf->pf_op = op;
|
||||
pf->pf_cookie = cookie;
|
||||
pf->pf_start = start;
|
||||
pf->pf_end = end;
|
||||
|
||||
rv = puffs_framev_enqueue_cc(puffs_cc_getcc(pu),
|
||||
puffs_getselectable(pu), pb, 0);
|
||||
|
||||
out:
|
||||
puffs_framebuf_destroy(pb);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_inval_namecache_dir(struct puffs_usermount *pu, puffs_cookie_t cookie)
|
||||
{
|
||||
|
||||
return doflush(pu, cookie, PUFFS_INVAL_NAMECACHE_DIR, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_inval_namecache_all(struct puffs_usermount *pu)
|
||||
{
|
||||
|
||||
return doflush(pu, NULL, PUFFS_INVAL_NAMECACHE_ALL, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_inval_pagecache_node(struct puffs_usermount *pu, puffs_cookie_t cookie)
|
||||
{
|
||||
|
||||
return doflush(pu, cookie, PUFFS_INVAL_PAGECACHE_NODE_RANGE, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_inval_pagecache_node_range(struct puffs_usermount *pu,
|
||||
puffs_cookie_t cookie, off_t start, off_t end)
|
||||
{
|
||||
|
||||
return doflush(pu, cookie, PUFFS_INVAL_PAGECACHE_NODE_RANGE, start,end);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_flush_pagecache_node(struct puffs_usermount *pu, puffs_cookie_t cookie)
|
||||
{
|
||||
|
||||
return doflush(pu, cookie, PUFFS_FLUSH_PAGECACHE_NODE_RANGE, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_flush_pagecache_node_range(struct puffs_usermount *pu,
|
||||
puffs_cookie_t cookie, off_t start, off_t end)
|
||||
{
|
||||
|
||||
return doflush(pu, cookie, PUFFS_FLUSH_PAGECACHE_NODE_RANGE, start,end);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,683 +0,0 @@
|
|||
/* $NetBSD: null.c,v 1.33 2011/11/25 15:02:02 manu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: null.c,v 1.33 2011/11/25 15:02:02 manu Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
/*
|
||||
* A "nullfs" using puffs, i.e. maps one location in the hierarchy
|
||||
* to another using standard system calls.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <puffs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
PUFFSOP_PROTOS(puffs_null)
|
||||
|
||||
/*
|
||||
* set attributes to what is specified. XXX: no rollback in case of failure
|
||||
*/
|
||||
static int
|
||||
processvattr(const char *path, const struct vattr *va, int regular)
|
||||
{
|
||||
struct timeval tv[2];
|
||||
|
||||
/* XXX: -1 == PUFFS_VNOVAL, but shouldn't trust that */
|
||||
if (va->va_uid != (unsigned)-1 || va->va_gid != (unsigned)-1)
|
||||
if (lchown(path, va->va_uid, va->va_gid) == -1)
|
||||
return errno;
|
||||
|
||||
if (va->va_mode != (unsigned)PUFFS_VNOVAL)
|
||||
if (lchmod(path, va->va_mode) == -1)
|
||||
return errno;
|
||||
|
||||
/* sloppy */
|
||||
if (va->va_atime.tv_sec != (time_t)PUFFS_VNOVAL
|
||||
|| va->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &va->va_atime);
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &va->va_mtime);
|
||||
|
||||
if (lutimes(path, tv) == -1)
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (regular && va->va_size != (u_quad_t)PUFFS_VNOVAL)
|
||||
if (truncate(path, (off_t)va->va_size) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kludge to open files which aren't writable *any longer*. This kinda
|
||||
* works because the vfs layer does validation checks based on the file's
|
||||
* permissions to allow writable opening before opening them. However,
|
||||
* the problem arises if we want to create a file, write to it (cache),
|
||||
* adjust permissions and then flush the file.
|
||||
*/
|
||||
static int
|
||||
writeableopen(const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
mode_t origmode;
|
||||
int sverr = 0;
|
||||
int fd;
|
||||
|
||||
fd = open(path, O_WRONLY);
|
||||
if (fd == -1) {
|
||||
if (errno == EACCES) {
|
||||
if (stat(path, &sb) == -1)
|
||||
return -1;
|
||||
origmode = sb.st_mode & ALLPERMS;
|
||||
|
||||
if (chmod(path, 0200) == -1)
|
||||
return -1;
|
||||
|
||||
fd = open(path, O_WRONLY);
|
||||
if (fd == -1)
|
||||
sverr = errno;
|
||||
|
||||
chmod(path, origmode);
|
||||
if (sverr)
|
||||
errno = sverr;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void *
|
||||
inodecmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
|
||||
{
|
||||
ino_t *cmpino = arg;
|
||||
|
||||
if (pn->pn_va.va_fileid == *cmpino)
|
||||
return pn;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
makenode(struct puffs_usermount *pu, struct puffs_newinfo *pni,
|
||||
const struct puffs_cn *pcn, const struct vattr *va, int regular)
|
||||
{
|
||||
struct puffs_node *pn;
|
||||
struct stat sb;
|
||||
int rv;
|
||||
|
||||
if ((rv = processvattr(PCNPATH(pcn), va, regular)) != 0)
|
||||
return rv;
|
||||
|
||||
pn = puffs_pn_new(pu, NULL);
|
||||
if (!pn)
|
||||
return ENOMEM;
|
||||
puffs_setvattr(&pn->pn_va, va);
|
||||
|
||||
if (lstat(PCNPATH(pcn), &sb) == -1)
|
||||
return errno;
|
||||
puffs_stat2vattr(&pn->pn_va, &sb);
|
||||
|
||||
puffs_newinfo_setcookie(pni, pn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This should be called first and overriden from the file system */
|
||||
void
|
||||
puffs_null_setops(struct puffs_ops *pops)
|
||||
{
|
||||
|
||||
PUFFSOP_SET(pops, puffs_null, fs, statvfs);
|
||||
PUFFSOP_SETFSNOP(pops, unmount);
|
||||
PUFFSOP_SETFSNOP(pops, sync);
|
||||
PUFFSOP_SET(pops, puffs_null, fs, fhtonode);
|
||||
PUFFSOP_SET(pops, puffs_null, fs, nodetofh);
|
||||
|
||||
PUFFSOP_SET(pops, puffs_null, node, lookup);
|
||||
PUFFSOP_SET(pops, puffs_null, node, create);
|
||||
PUFFSOP_SET(pops, puffs_null, node, mknod);
|
||||
PUFFSOP_SET(pops, puffs_null, node, getattr);
|
||||
PUFFSOP_SET(pops, puffs_null, node, setattr);
|
||||
PUFFSOP_SET(pops, puffs_null, node, fsync);
|
||||
PUFFSOP_SET(pops, puffs_null, node, remove);
|
||||
PUFFSOP_SET(pops, puffs_null, node, link);
|
||||
PUFFSOP_SET(pops, puffs_null, node, rename);
|
||||
PUFFSOP_SET(pops, puffs_null, node, mkdir);
|
||||
PUFFSOP_SET(pops, puffs_null, node, rmdir);
|
||||
PUFFSOP_SET(pops, puffs_null, node, symlink);
|
||||
PUFFSOP_SET(pops, puffs_null, node, readlink);
|
||||
PUFFSOP_SET(pops, puffs_null, node, readdir);
|
||||
PUFFSOP_SET(pops, puffs_null, node, read);
|
||||
PUFFSOP_SET(pops, puffs_null, node, write);
|
||||
PUFFSOP_SET(pops, puffs_genfs, node, reclaim);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_fs_statvfs(struct puffs_usermount *pu, struct statvfs *svfsb)
|
||||
{
|
||||
|
||||
if (statvfs(PNPATH(puffs_getroot(pu)), svfsb) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: this is the stupidest crap ever, but:
|
||||
* getfh() returns the fhandle type, when we are expected to deliver
|
||||
* the fid type. Just adjust it a bit and stop whining.
|
||||
*
|
||||
* Yes, this really really needs fixing. Yes, *REALLY*.
|
||||
*/
|
||||
#define FHANDLE_HEADERLEN 8
|
||||
struct kernfid {
|
||||
unsigned short fid_len; /* length of data in bytes */
|
||||
unsigned short fid_reserved; /* compat: historic align */
|
||||
char fid_data[0]; /* data (variable length) */
|
||||
};
|
||||
|
||||
/*ARGSUSED*/
|
||||
static void *
|
||||
fhcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
|
||||
{
|
||||
struct kernfid *kf1, *kf2;
|
||||
|
||||
if ((kf1 = pn->pn_data) == NULL)
|
||||
return NULL;
|
||||
kf2 = arg;
|
||||
|
||||
if (kf1->fid_len != kf2->fid_len)
|
||||
return NULL;
|
||||
|
||||
/*LINTED*/
|
||||
if (memcmp(kf1, kf2, kf1->fid_len) == 0)
|
||||
return pn;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine only supports file handles which have been issued while
|
||||
* the server was alive. Not really stable ones, that is.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
|
||||
struct puffs_newinfo *pni)
|
||||
{
|
||||
struct puffs_node *pn_res;
|
||||
|
||||
pn_res = puffs_pn_nodewalk(pu, fhcmp, fid);
|
||||
if (pn_res == NULL)
|
||||
return ENOENT;
|
||||
|
||||
puffs_newinfo_setcookie(pni, pn_res);
|
||||
puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
|
||||
puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
|
||||
puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
void *fid, size_t *fidsize)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
struct kernfid *kfid;
|
||||
void *bounce;
|
||||
int rv;
|
||||
|
||||
rv = 0;
|
||||
bounce = NULL;
|
||||
if (*fidsize) {
|
||||
bounce = malloc(*fidsize + FHANDLE_HEADERLEN);
|
||||
if (!bounce)
|
||||
return ENOMEM;
|
||||
*fidsize += FHANDLE_HEADERLEN;
|
||||
}
|
||||
if (getfh(PNPATH(pn), bounce, fidsize) == -1)
|
||||
rv = errno;
|
||||
else
|
||||
memcpy(fid, (uint8_t *)bounce + FHANDLE_HEADERLEN,
|
||||
*fidsize - FHANDLE_HEADERLEN);
|
||||
kfid = fid;
|
||||
if (rv == 0) {
|
||||
*fidsize = kfid->fid_len;
|
||||
pn->pn_data = malloc(*fidsize);
|
||||
if (pn->pn_data == NULL)
|
||||
abort(); /* lazy */
|
||||
memcpy(pn->pn_data, fid, *fidsize);
|
||||
} else {
|
||||
*fidsize -= FHANDLE_HEADERLEN;
|
||||
}
|
||||
free(bounce);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
puffs_null_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct puffs_newinfo *pni, const struct puffs_cn *pcn)
|
||||
{
|
||||
struct puffs_node *pn = opc, *pn_res;
|
||||
struct stat sb;
|
||||
int rv;
|
||||
|
||||
assert(pn->pn_va.va_type == VDIR);
|
||||
|
||||
/*
|
||||
* Note to whoever is copypasting this: you must first check
|
||||
* if the node is there and only then do nodewalk. Alternatively
|
||||
* you could make sure that you don't return unlinked/rmdir'd
|
||||
* nodes in some other fashion
|
||||
*/
|
||||
rv = lstat(PCNPATH(pcn), &sb);
|
||||
if (rv)
|
||||
return errno;
|
||||
|
||||
/* XXX2: nodewalk is a bit too slow here */
|
||||
pn_res = puffs_pn_nodewalk(pu, inodecmp, &sb.st_ino);
|
||||
|
||||
if (pn_res == NULL) {
|
||||
pn_res = puffs_pn_new(pu, NULL);
|
||||
if (pn_res == NULL)
|
||||
return ENOMEM;
|
||||
puffs_stat2vattr(&pn_res->pn_va, &sb);
|
||||
}
|
||||
|
||||
puffs_newinfo_setcookie(pni, pn_res);
|
||||
puffs_newinfo_setvtype(pni, pn_res->pn_va.va_type);
|
||||
puffs_newinfo_setsize(pni, (voff_t)pn_res->pn_va.va_size);
|
||||
puffs_newinfo_setrdev(pni, pn_res->pn_va.va_rdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct puffs_newinfo *pni, const struct puffs_cn *pcn,
|
||||
const struct vattr *va)
|
||||
{
|
||||
int fd, rv;
|
||||
|
||||
fd = open(PCNPATH(pcn), O_RDWR | O_CREAT | O_TRUNC);
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
close(fd);
|
||||
|
||||
rv = makenode(pu, pni, pcn, va, 1);
|
||||
if (rv)
|
||||
unlink(PCNPATH(pcn));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct puffs_newinfo *pni, const struct puffs_cn *pcn,
|
||||
const struct vattr *va)
|
||||
{
|
||||
mode_t mode;
|
||||
int rv;
|
||||
|
||||
mode = puffs_addvtype2mode(va->va_mode, va->va_type);
|
||||
if (mknod(PCNPATH(pcn), mode, va->va_rdev) == -1)
|
||||
return errno;
|
||||
|
||||
rv = makenode(pu, pni, pcn, va, 0);
|
||||
if (rv)
|
||||
unlink(PCNPATH(pcn));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct vattr *va, const struct puffs_cred *pcred)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
struct stat sb;
|
||||
|
||||
if (lstat(PNPATH(pn), &sb) == -1)
|
||||
return errno;
|
||||
puffs_stat2vattr(va, &sb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
const struct vattr *va, const struct puffs_cred *pcred)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
int rv;
|
||||
|
||||
rv = processvattr(PNPATH(pn), va, pn->pn_va.va_type == VREG);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
puffs_setvattr(&pn->pn_va, va);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
const struct puffs_cred *pcred, int how,
|
||||
off_t offlo, off_t offhi)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
int fd, rv;
|
||||
int fflags;
|
||||
struct stat sb;
|
||||
|
||||
rv = 0;
|
||||
if (stat(PNPATH(pn), &sb) == -1)
|
||||
return errno;
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
DIR *dirp;
|
||||
if ((dirp = opendir(PNPATH(pn))) == 0)
|
||||
return errno;
|
||||
fd = dirfd(dirp);
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
|
||||
if (fsync(fd) == -1)
|
||||
rv = errno;
|
||||
} else {
|
||||
fd = writeableopen(PNPATH(pn));
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
|
||||
if (how & PUFFS_FSYNC_DATAONLY)
|
||||
fflags = FDATASYNC;
|
||||
else
|
||||
fflags = FFILESYNC;
|
||||
if (how & PUFFS_FSYNC_CACHE)
|
||||
fflags |= FDISKSYNC;
|
||||
|
||||
if (fsync_range(fd, fflags, offlo, offhi - offlo) == -1)
|
||||
rv = errno;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
puffs_cookie_t targ, const struct puffs_cn *pcn)
|
||||
{
|
||||
struct puffs_node *pn_targ = targ;
|
||||
|
||||
if (unlink(PNPATH(pn_targ)) == -1)
|
||||
return errno;
|
||||
puffs_pn_remove(pn_targ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
puffs_cookie_t targ, const struct puffs_cn *pcn)
|
||||
{
|
||||
struct puffs_node *pn_targ = targ;
|
||||
|
||||
if (link(PNPATH(pn_targ), PCNPATH(pcn)) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
puffs_cookie_t src, const struct puffs_cn *pcn_src,
|
||||
puffs_cookie_t targ_dir, puffs_cookie_t targ,
|
||||
const struct puffs_cn *pcn_targ)
|
||||
{
|
||||
struct puffs_node *pn_targ = targ;
|
||||
|
||||
if (rename(PCNPATH(pcn_src), PCNPATH(pcn_targ)) == -1)
|
||||
return errno;
|
||||
|
||||
if (pn_targ)
|
||||
puffs_pn_remove(pn_targ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct puffs_newinfo *pni, const struct puffs_cn *pcn,
|
||||
const struct vattr *va)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (mkdir(PCNPATH(pcn), va->va_mode) == -1)
|
||||
return errno;
|
||||
|
||||
rv = makenode(pu, pni, pcn, va, 0);
|
||||
if (rv)
|
||||
rmdir(PCNPATH(pcn));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
puffs_cookie_t targ, const struct puffs_cn *pcn)
|
||||
{
|
||||
struct puffs_node *pn_targ = targ;
|
||||
|
||||
if (rmdir(PNPATH(pn_targ)) == -1)
|
||||
return errno;
|
||||
puffs_pn_remove(pn_targ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct puffs_newinfo *pni, const struct puffs_cn *pcn,
|
||||
const struct vattr *va, const char *linkname)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (symlink(linkname, PCNPATH(pcn)) == -1)
|
||||
return errno;
|
||||
|
||||
rv = makenode(pu, pni, pcn, va, 0);
|
||||
if (rv)
|
||||
unlink(PCNPATH(pcn));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
const struct puffs_cred *pcred, char *linkname, size_t *linklen)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
ssize_t rv;
|
||||
|
||||
rv = readlink(PNPATH(pn), linkname, *linklen);
|
||||
if (rv == -1)
|
||||
return errno;
|
||||
|
||||
*linklen = rv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct dirent *de, off_t *off, size_t *reslen,
|
||||
const struct puffs_cred *pcred, int *eofflag, off_t *cookies,
|
||||
size_t *ncookies)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
struct dirent entry, *result;
|
||||
DIR *dp;
|
||||
off_t i;
|
||||
int rv;
|
||||
|
||||
*ncookies = 0;
|
||||
dp = opendir(PNPATH(pn));
|
||||
if (dp == NULL)
|
||||
return errno;
|
||||
|
||||
rv = 0;
|
||||
i = *off;
|
||||
|
||||
/*
|
||||
* XXX: need to do trickery here, telldir/seekdir would be nice, but
|
||||
* then we'd need to keep state, which I'm too lazy to keep
|
||||
*/
|
||||
while (i--) {
|
||||
rv = readdir_r(dp, &entry, &result);
|
||||
if (rv != 0)
|
||||
goto out;
|
||||
|
||||
if (!result) {
|
||||
*eofflag = 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
rv = readdir_r(dp, &entry, &result);
|
||||
if (rv != 0)
|
||||
goto out;
|
||||
|
||||
if (!result) {
|
||||
*eofflag = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (_DIRENT_SIZE(result) > *reslen)
|
||||
goto out;
|
||||
|
||||
*de = *result;
|
||||
*reslen -= _DIRENT_SIZE(result);
|
||||
de = _DIRENT_NEXT(de);
|
||||
|
||||
(*off)++;
|
||||
PUFFS_STORE_DCOOKIE(cookies, ncookies, *off);
|
||||
}
|
||||
|
||||
out:
|
||||
closedir(dp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
uint8_t *buf, off_t offset, size_t *buflen,
|
||||
const struct puffs_cred *pcred, int ioflag)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
ssize_t n;
|
||||
off_t off;
|
||||
int fd, rv;
|
||||
|
||||
rv = 0;
|
||||
fd = open(PNPATH(pn), O_RDONLY);
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
off = lseek(fd, offset, SEEK_SET);
|
||||
if (off == -1) {
|
||||
rv = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
n = read(fd, buf, *buflen);
|
||||
if (n == -1)
|
||||
rv = errno;
|
||||
else
|
||||
*buflen -= n;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
uint8_t *buf, off_t offset, size_t *buflen,
|
||||
const struct puffs_cred *pcred, int ioflag)
|
||||
{
|
||||
struct puffs_node *pn = opc;
|
||||
ssize_t n;
|
||||
off_t off;
|
||||
int fd, rv;
|
||||
|
||||
rv = 0;
|
||||
fd = writeableopen(PNPATH(pn));
|
||||
if (fd == -1)
|
||||
return errno;
|
||||
|
||||
off = lseek(fd, offset, SEEK_SET);
|
||||
if (off == -1) {
|
||||
rv = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
n = write(fd, buf, *buflen);
|
||||
if (n == -1)
|
||||
rv = errno;
|
||||
else
|
||||
*buflen -= n;
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return rv;
|
||||
}
|
||||
|
|
@ -1,542 +0,0 @@
|
|||
/* $NetBSD: opdump.c,v 1.37 2014/10/31 13:56:04 manu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2006 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Google Summer of Code program and the Ulla Tuominen Foundation.
|
||||
* The Google SoC project was mentored by Bill Studenmund.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Pretty-printing helper routines for VFS/VOP request contents */
|
||||
|
||||
/* yes, this is pretty much a mess */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: opdump.c,v 1.37 2014/10/31 13:56:04 manu Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <puffs.h>
|
||||
#include <puffsdump.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
#define DINT " "
|
||||
|
||||
const char *puffsdump_vfsop_revmap[] = {
|
||||
"PUFFS_VFS_MOUNT",
|
||||
"PUFFS_VFS_START",
|
||||
"PUFFS_VFS_UNMOUNT",
|
||||
"PUFFS_VFS_ROOT",
|
||||
"PUFFS_VFS_QUOTACTL",
|
||||
"PUFFS_VFS_STATVFS",
|
||||
"PUFFS_VFS_SYNC",
|
||||
"PUFFS_VFS_VGET",
|
||||
"PUFFS_VFS_FHTOVP",
|
||||
"PUFFS_VFS_VPTOFH",
|
||||
"PUFFS_VFS_INIT",
|
||||
"PUFFS_VFS_DONE",
|
||||
"PUFFS_VFS_SNAPSHOT",
|
||||
"PUFFS_VFS_EXTATTRCTL",
|
||||
"PUFFS_VFS_SUSPEND"
|
||||
};
|
||||
size_t puffsdump_vfsop_count = __arraycount(puffsdump_vfsop_revmap);
|
||||
|
||||
const char *puffsdump_vnop_revmap[] = {
|
||||
"PUFFS_VN_LOOKUP",
|
||||
"PUFFS_VN_CREATE",
|
||||
"PUFFS_VN_MKNOD",
|
||||
"PUFFS_VN_OPEN",
|
||||
"PUFFS_VN_CLOSE",
|
||||
"PUFFS_VN_ACCESS",
|
||||
"PUFFS_VN_GETATTR",
|
||||
"PUFFS_VN_SETATTR",
|
||||
"PUFFS_VN_READ",
|
||||
"PUFFS_VN_WRITE",
|
||||
"PUFFS_VN_IOCTL",
|
||||
"PUFFS_VN_FCNTL",
|
||||
"PUFFS_VN_POLL",
|
||||
"PUFFS_VN_KQFILTER",
|
||||
"PUFFS_VN_REVOKE",
|
||||
"PUFFS_VN_MMAP",
|
||||
"PUFFS_VN_FSYNC",
|
||||
"PUFFS_VN_SEEK",
|
||||
"PUFFS_VN_REMOVE",
|
||||
"PUFFS_VN_LINK",
|
||||
"PUFFS_VN_RENAME",
|
||||
"PUFFS_VN_MKDIR",
|
||||
"PUFFS_VN_RMDIR",
|
||||
"PUFFS_VN_SYMLINK",
|
||||
"PUFFS_VN_READDIR",
|
||||
"PUFFS_VN_READLINK",
|
||||
"PUFFS_VN_ABORTOP",
|
||||
"PUFFS_VN_INACTIVE",
|
||||
"PUFFS_VN_RECLAIM",
|
||||
"PUFFS_VN_LOCK",
|
||||
"PUFFS_VN_UNLOCK",
|
||||
"PUFFS_VN_BMAP",
|
||||
"PUFFS_VN_STRATEGY",
|
||||
"PUFFS_VN_PRINT",
|
||||
"PUFFS_VN_ISLOCKED",
|
||||
"PUFFS_VN_PATHCONF",
|
||||
"PUFFS_VN_ADVLOCK",
|
||||
"PUFFS_VN_LEASE",
|
||||
"PUFFS_VN_WHITEOUT",
|
||||
"PUFFS_VN_GETPAGES",
|
||||
"PUFFS_VN_PUTPAGES",
|
||||
"PUFFS_VN_GETEXTATTR",
|
||||
"PUFFS_VN_LISTEXTATTR",
|
||||
"PUFFS_VN_OPENEXTATTR",
|
||||
"PUFFS_VN_DELETEEXTATTR",
|
||||
"PUFFS_VN_SETEXTATTR",
|
||||
"PUFFS_VN_CLOSEEXTATTR",
|
||||
"PUFFS_VN_FALLOCATE",
|
||||
"PUFFS_VN_FDISCARD",
|
||||
};
|
||||
size_t puffsdump_vnop_count = __arraycount(puffsdump_vnop_revmap);
|
||||
|
||||
/* XXX! */
|
||||
const char *puffsdump_cacheop_revmap[] = {
|
||||
"PUFFS_CACHE_WRITE"
|
||||
};
|
||||
|
||||
const char *puffsdump_errnot_revmap[] = {
|
||||
"PUFFS_ERR_ERROR",
|
||||
"PUFFS_ERR_MAKENODE",
|
||||
"PUFFS_ERR_LOOKUP",
|
||||
"PUFFS_ERR_READDIR",
|
||||
"PUFFS_ERR_READLINK",
|
||||
"PUFFS_ERR_READ",
|
||||
"PUFFS_ERR_WRITE",
|
||||
"PUFFS_ERR_VPTOFH",
|
||||
"PUFFS_ERR_GETEXTATTR",
|
||||
"PUFFS_ERR_LISTEXTATTR",
|
||||
};
|
||||
size_t puffsdump_errnot_count = __arraycount(puffsdump_errnot_revmap);
|
||||
|
||||
const char *puffsdump_flush_revmap[] = {
|
||||
"PUFFS_INVAL_NAMECACHE_NODE",
|
||||
"PUFFS_INVAL_NAMECACHE_DIR",
|
||||
"PUFFS_INVAL_NAMECACHE_ALL",
|
||||
"PUFFS_INVAL_PAGECACHE_NODE_RANGE",
|
||||
"PUFFS_FLUSH_PAGECACHE_NODE_RANGE",
|
||||
};
|
||||
size_t puffsdump_flush_count = __arraycount(puffsdump_flush_revmap);
|
||||
|
||||
static __printflike(1, 2) void
|
||||
mydprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_req(struct puffs_req *preq)
|
||||
{
|
||||
char buf[128];
|
||||
static struct timeval tv_prev;
|
||||
struct timeval tv_now, tv;
|
||||
const char **map;
|
||||
const char *optype;
|
||||
size_t maxhandle;
|
||||
int opclass, isvn = 0;
|
||||
|
||||
mydprintf("reqid: %" PRIu64 ", ", preq->preq_id);
|
||||
opclass = PUFFSOP_OPCLASS(preq->preq_opclass);
|
||||
switch (opclass) {
|
||||
case PUFFSOP_VFS:
|
||||
map = puffsdump_vfsop_revmap;
|
||||
maxhandle = puffsdump_vfsop_count;
|
||||
break;
|
||||
case PUFFSOP_VN:
|
||||
map = puffsdump_vnop_revmap;
|
||||
maxhandle = puffsdump_vnop_count;
|
||||
isvn = 1;
|
||||
break;
|
||||
case PUFFSOP_CACHE:
|
||||
map = puffsdump_cacheop_revmap;
|
||||
maxhandle = __arraycount(puffsdump_cacheop_revmap);
|
||||
break;
|
||||
case PUFFSOP_ERROR:
|
||||
map = puffsdump_errnot_revmap;
|
||||
maxhandle = puffsdump_errnot_count;
|
||||
break;
|
||||
case PUFFSOP_FLUSH:
|
||||
map = puffsdump_flush_revmap;
|
||||
maxhandle = puffsdump_flush_count;
|
||||
break;
|
||||
default:
|
||||
mydprintf("unhandled opclass %d\n", opclass);
|
||||
return;
|
||||
}
|
||||
|
||||
if (preq->preq_optype < maxhandle) {
|
||||
optype = map[preq->preq_optype];
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "UNKNOWN (%d)", preq->preq_optype);
|
||||
optype = buf;
|
||||
}
|
||||
|
||||
mydprintf("opclass %d%s, optype: %s, "
|
||||
"cookie: %p,\n" DINT "aux: %p, auxlen: %zu, pid: %d, lwpid: %d\n",
|
||||
opclass, PUFFSOP_WANTREPLY(preq->preq_opclass) ? "" : " (FAF)",
|
||||
optype, preq->preq_cookie,
|
||||
preq->preq_buf, preq->preq_buflen,
|
||||
preq->preq_pid, preq->preq_lid);
|
||||
|
||||
if (isvn) {
|
||||
switch (preq->preq_optype) {
|
||||
case PUFFS_VN_LOOKUP:
|
||||
puffsdump_lookup(preq);
|
||||
break;
|
||||
case PUFFS_VN_READ:
|
||||
case PUFFS_VN_WRITE:
|
||||
puffsdump_readwrite(preq);
|
||||
break;
|
||||
case PUFFS_VN_OPEN:
|
||||
puffsdump_open(preq);
|
||||
break;
|
||||
case PUFFS_VN_REMOVE:
|
||||
case PUFFS_VN_RMDIR:
|
||||
case PUFFS_VN_LINK:
|
||||
puffsdump_targ(preq);
|
||||
break;
|
||||
case PUFFS_VN_READDIR:
|
||||
puffsdump_readdir(preq);
|
||||
break;
|
||||
case PUFFS_VN_CREATE:
|
||||
case PUFFS_VN_MKDIR:
|
||||
case PUFFS_VN_MKNOD:
|
||||
case PUFFS_VN_SYMLINK:
|
||||
puffsdump_create(preq);
|
||||
break;
|
||||
case PUFFS_VN_SETATTR:
|
||||
puffsdump_attr(preq);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PU_LOCK();
|
||||
gettimeofday(&tv_now, NULL);
|
||||
timersub(&tv_now, &tv_prev, &tv);
|
||||
mydprintf(DINT "since previous call: %lld.%06ld\n",
|
||||
(long long)tv.tv_sec, (long)tv.tv_usec);
|
||||
gettimeofday(&tv_prev, NULL);
|
||||
PU_UNLOCK();
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_rv(struct puffs_req *preq)
|
||||
{
|
||||
|
||||
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
|
||||
switch (preq->preq_optype) {
|
||||
case PUFFS_VN_LOOKUP:
|
||||
puffsdump_lookup_rv(preq);
|
||||
break;
|
||||
case PUFFS_VN_CREATE:
|
||||
case PUFFS_VN_MKDIR:
|
||||
case PUFFS_VN_MKNOD:
|
||||
case PUFFS_VN_SYMLINK:
|
||||
puffsdump_create_rv(preq);
|
||||
break;
|
||||
case PUFFS_VN_READ:
|
||||
case PUFFS_VN_WRITE:
|
||||
puffsdump_readwrite_rv(preq);
|
||||
break;
|
||||
case PUFFS_VN_READDIR:
|
||||
puffsdump_readdir_rv(preq);
|
||||
break;
|
||||
case PUFFS_VN_GETATTR:
|
||||
puffsdump_attr(preq);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mydprintf("RV reqid: %" PRIu64 ", result: %d %s\n",
|
||||
preq->preq_id, preq->preq_rv,
|
||||
preq->preq_rv ? strerror(preq->preq_rv) : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Slightly tedious print-routine so that we get a nice NOVAL instead
|
||||
* of some tedious output representations for -1, especially (uint64_t)-1
|
||||
*
|
||||
* We use typecasting to make this work beyond time_t/dev_t size changes.
|
||||
*/
|
||||
static void
|
||||
dumpattr(struct vattr *vap)
|
||||
{
|
||||
const char * const vtypes[] = { VNODE_TYPES };
|
||||
char buf[128];
|
||||
|
||||
/* XXX: better readability. and this is debug, so no cycle-sweat */
|
||||
#define DEFAULTBUF() snprintf(buf, sizeof(buf), "NOVAL")
|
||||
|
||||
mydprintf(DINT "vattr:\n");
|
||||
mydprintf(DINT DINT "type: %s, ", vtypes[vap->va_type]);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_mode != (mode_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "0%o", vap->va_mode);
|
||||
mydprintf("mode: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_nlink != (nlink_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%d", vap->va_nlink);
|
||||
mydprintf("nlink: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_uid != (uid_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%d", vap->va_uid);
|
||||
mydprintf("uid: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_gid != (gid_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%d", vap->va_gid);
|
||||
mydprintf("gid: %s\n", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if ((unsigned long long)vap->va_fsid!=(unsigned long long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "0x%llx",
|
||||
(unsigned long long)vap->va_fsid);
|
||||
mydprintf(DINT DINT "fsid: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_fileid != (ino_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_fileid);
|
||||
mydprintf("ino: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_size);
|
||||
mydprintf("size: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_blocksize != (long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%ld", vap->va_blocksize);
|
||||
mydprintf("bsize: %s\n", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%lld",
|
||||
(long long)vap->va_atime.tv_sec);
|
||||
mydprintf(DINT DINT "a.s: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_atime.tv_nsec != (long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%ld", vap->va_atime.tv_nsec);
|
||||
mydprintf("a.ns: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%lld",
|
||||
(long long)vap->va_mtime.tv_sec);
|
||||
mydprintf("m.s: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_mtime.tv_nsec != (long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%ld", vap->va_mtime.tv_nsec);
|
||||
mydprintf("m.ns: %s\n", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_ctime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%lld",
|
||||
(long long)vap->va_ctime.tv_sec);
|
||||
mydprintf(DINT DINT "c.s: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_ctime.tv_nsec != (long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%ld", vap->va_ctime.tv_nsec);
|
||||
mydprintf("c.ns: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_birthtime.tv_sec != (time_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%lld",
|
||||
(long long)vap->va_birthtime.tv_sec);
|
||||
mydprintf("b.s: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_birthtime.tv_nsec != (long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%ld", vap->va_birthtime.tv_nsec);
|
||||
mydprintf("b.ns: %s\n", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_gen != (u_long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%lu", vap->va_gen);
|
||||
mydprintf(DINT DINT "gen: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_flags != (u_long)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "0x%lx", vap->va_flags);
|
||||
mydprintf("flags: %s, ", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_rdev != (dev_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "0x%llx",
|
||||
(unsigned long long)vap->va_rdev);
|
||||
mydprintf("rdev: %s\n", buf);
|
||||
|
||||
DEFAULTBUF();
|
||||
if (vap->va_bytes != (u_quad_t)PUFFS_VNOVAL)
|
||||
snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_bytes);
|
||||
mydprintf(DINT DINT "bytes: %s, ", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%" PRIu64, vap->va_filerev);
|
||||
mydprintf("filerev: %s, ", buf);
|
||||
|
||||
snprintf(buf, sizeof(buf), "0x%x", vap->va_vaflags);
|
||||
mydprintf("vaflags: %s\n", buf);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_cookie(puffs_cookie_t c, const char *cookiename)
|
||||
{
|
||||
|
||||
mydprintf("%scookie: at %p\n", cookiename, c);
|
||||
}
|
||||
|
||||
static const char *cn_opnames[] = {
|
||||
"LOOKUP",
|
||||
"CREATE",
|
||||
"DELETE",
|
||||
"RENAME"
|
||||
};
|
||||
|
||||
void
|
||||
puffsdump_cn(struct puffs_kcn *pkcn)
|
||||
{
|
||||
|
||||
mydprintf(DINT "puffs_cn: \"%s\", len %zu op %s (flags 0x%x)\n",
|
||||
pkcn->pkcn_name, pkcn->pkcn_namelen,
|
||||
cn_opnames[pkcn->pkcn_nameiop & NAMEI_OPMASK],
|
||||
pkcn->pkcn_flags);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_lookup(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_lookup *lookup_msg = (void *)preq;
|
||||
|
||||
puffsdump_cn(&lookup_msg->pvnr_cn);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_lookup_rv(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_lookup *lookup_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "new %p, type 0x%x, size 0x%"PRIu64", dev 0x%llx\n",
|
||||
lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
|
||||
lookup_msg->pvnr_size, (unsigned long long)lookup_msg->pvnr_rdev);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_create(struct puffs_req *preq)
|
||||
{
|
||||
/* XXX: wrong type, but we know it fits the slot */
|
||||
struct puffs_vnmsg_create *create_msg = (void *)preq;
|
||||
|
||||
dumpattr(&create_msg->pvnr_va);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_create_rv(struct puffs_req *preq)
|
||||
{
|
||||
/* XXX: wrong type, but we know it fits the slot */
|
||||
struct puffs_vnmsg_create *create_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "new %p\n", create_msg->pvnr_newnode);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_readwrite(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_rw *rw_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "offset: %" PRId64 ", resid %zu, ioflag 0x%x\n",
|
||||
rw_msg->pvnr_offset, rw_msg->pvnr_resid, rw_msg->pvnr_ioflag);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_readwrite_rv(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_rw *rw_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "resid after op: %zu\n", rw_msg->pvnr_resid);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_readdir_rv(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_readdir *readdir_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "resid after op: %zu, eofflag %d\n",
|
||||
readdir_msg->pvnr_resid, readdir_msg->pvnr_eofflag);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_open(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_open *open_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "mode: 0x%x\n", open_msg->pvnr_mode);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_targ(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_remove *remove_msg = (void *)preq; /* XXX! */
|
||||
|
||||
mydprintf(DINT "target cookie: %p\n", remove_msg->pvnr_cookie_targ);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_readdir(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_readdir *readdir_msg = (void *)preq;
|
||||
|
||||
mydprintf(DINT "read offset: %" PRId64 "\n", readdir_msg->pvnr_offset);
|
||||
}
|
||||
|
||||
void
|
||||
puffsdump_attr(struct puffs_req *preq)
|
||||
{
|
||||
struct puffs_vnmsg_setgetattr *attr_msg = (void *)preq;
|
||||
|
||||
dumpattr(&attr_msg->pvnr_va);
|
||||
}
|
||||
|
|
@ -1,299 +0,0 @@
|
|||
/* $NetBSD: paths.c,v 1.8 2008/08/12 19:44:39 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: paths.c,v 1.8 2008/08/12 19:44:39 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/hash.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
/*
|
||||
* Generic routines for pathbuilding code
|
||||
*/
|
||||
|
||||
int
|
||||
puffs_path_pcnbuild(struct puffs_usermount *pu, struct puffs_cn *pcn,
|
||||
puffs_cookie_t parent)
|
||||
{
|
||||
struct puffs_node *pn_parent = PU_CMAP(pu, parent);
|
||||
struct puffs_cn pcn_orig;
|
||||
struct puffs_pathobj po;
|
||||
int rv;
|
||||
|
||||
assert(pn_parent->pn_po.po_path != NULL);
|
||||
assert(pu->pu_flags & PUFFS_FLAG_BUILDPATH);
|
||||
|
||||
if (pu->pu_pathtransform) {
|
||||
rv = pu->pu_pathtransform(pu, &pn_parent->pn_po, pcn, &po);
|
||||
if (rv)
|
||||
return rv;
|
||||
} else {
|
||||
po.po_path = pcn->pcn_name;
|
||||
po.po_len = pcn->pcn_namelen;
|
||||
}
|
||||
|
||||
if (pu->pu_namemod) {
|
||||
/* XXX: gcc complains if I do assignment */
|
||||
memcpy(&pcn_orig, pcn, sizeof(pcn_orig));
|
||||
rv = pu->pu_namemod(pu, &pn_parent->pn_po, pcn);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = pu->pu_pathbuild(pu, &pn_parent->pn_po, &po, 0,
|
||||
&pcn->pcn_po_full);
|
||||
puffs_path_buildhash(pu, &pcn->pcn_po_full);
|
||||
|
||||
if (pu->pu_pathtransform)
|
||||
pu->pu_pathfree(pu, &po);
|
||||
|
||||
if (pu->pu_namemod && rv)
|
||||
*pcn = pcn_orig;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* substitute all (child) patch prefixes. called from nodewalk, which
|
||||
* in turn is called from rename
|
||||
*/
|
||||
void *
|
||||
puffs_path_prefixadj(struct puffs_usermount *pu, struct puffs_node *pn,
|
||||
void *arg)
|
||||
{
|
||||
struct puffs_pathinfo *pi = arg;
|
||||
struct puffs_pathobj localpo;
|
||||
struct puffs_pathobj oldpo;
|
||||
int rv;
|
||||
|
||||
/* can't be a path prefix */
|
||||
if (pn->pn_po.po_len < pi->pi_old->po_len)
|
||||
return NULL;
|
||||
|
||||
if (pu->pu_pathcmp(pu, &pn->pn_po, pi->pi_old, pi->pi_old->po_len, 1))
|
||||
return NULL;
|
||||
|
||||
/* otherwise we'd have two nodes with an equal path */
|
||||
assert(pn->pn_po.po_len > pi->pi_old->po_len);
|
||||
|
||||
/* found a matching prefix */
|
||||
rv = pu->pu_pathbuild(pu, pi->pi_new, &pn->pn_po,
|
||||
pi->pi_old->po_len, &localpo);
|
||||
/*
|
||||
* XXX: technically we shouldn't fail, but this is the only
|
||||
* sensible thing to do here. If the buildpath routine fails,
|
||||
* we will have paths in an inconsistent state. Should fix this,
|
||||
* either by having two separate passes or by doing other tricks
|
||||
* to make an invalid path with BUILDPATHS acceptable.
|
||||
*/
|
||||
if (rv != 0)
|
||||
abort();
|
||||
|
||||
/* adjust hash sum */
|
||||
puffs_path_buildhash(pu, &localpo);
|
||||
|
||||
/* out with the old and in with the new */
|
||||
oldpo = pn->pn_po;
|
||||
pn->pn_po = localpo;
|
||||
pu->pu_pathfree(pu, &oldpo);
|
||||
|
||||
/* continue the walk */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* called from nodewalk, checks for exact match
|
||||
*/
|
||||
void *
|
||||
puffs_path_walkcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
|
||||
{
|
||||
struct puffs_pathobj *po = arg;
|
||||
struct puffs_pathobj po2;
|
||||
|
||||
if (po->po_len != PNPLEN(pn))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If hashing and the hash doesn't match, we know this is
|
||||
* definitely not a match. Otherwise check for collisions.
|
||||
*/
|
||||
if (pu->pu_flags & PUFFS_FLAG_HASHPATH)
|
||||
if (pn->pn_po.po_hash != po->po_hash)
|
||||
return NULL;
|
||||
|
||||
po2.po_path = PNPATH(pn);
|
||||
po2.po_len = PNPLEN(pn);
|
||||
|
||||
if (pu->pu_pathcmp(pu, po, &po2, PNPLEN(pn), 0) == 0)
|
||||
return pn;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash sum building routine. Use string hash if the buildpath routine
|
||||
* is the standard one, otherwise use binary hashes. A bit whimsical
|
||||
* way to choose the routine, but the binary works for strings also,
|
||||
* so don't sweat it.
|
||||
*/
|
||||
void
|
||||
puffs_path_buildhash(struct puffs_usermount *pu, struct puffs_pathobj *po)
|
||||
{
|
||||
|
||||
if ((pu->pu_flags & PUFFS_FLAG_HASHPATH) == 0)
|
||||
return;
|
||||
|
||||
if (pu->pu_pathbuild == puffs_stdpath_buildpath)
|
||||
po->po_hash = hash32_strn(po->po_path, po->po_len,
|
||||
HASH32_STR_INIT);
|
||||
else
|
||||
po->po_hash = hash32_buf(po->po_path, po->po_len,
|
||||
HASH32_BUF_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines provided to file systems which consider a path a tuple of
|
||||
* strings and / the component separator.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_stdpath_cmppath(struct puffs_usermount *pu, struct puffs_pathobj *c1,
|
||||
struct puffs_pathobj *c2, size_t clen, int checkprefix)
|
||||
{
|
||||
char *p;
|
||||
int rv;
|
||||
|
||||
rv = strncmp(c1->po_path, c2->po_path, clen);
|
||||
if (rv)
|
||||
return 1;
|
||||
|
||||
if (checkprefix == 0)
|
||||
return 0;
|
||||
|
||||
/* sanity for next step */
|
||||
if (!(c1->po_len > c2->po_len))
|
||||
return 1;
|
||||
|
||||
/* check if it's really a complete path prefix */
|
||||
p = c1->po_path;
|
||||
if ((*(p + clen)) != '/')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_stdpath_buildpath(struct puffs_usermount *pu,
|
||||
const struct puffs_pathobj *po_pre, const struct puffs_pathobj *po_comp,
|
||||
size_t offset, struct puffs_pathobj *newpath)
|
||||
{
|
||||
char *path, *pcomp;
|
||||
size_t plen, complen;
|
||||
size_t prelen;
|
||||
int isdotdot;
|
||||
|
||||
complen = po_comp->po_len - offset;
|
||||
|
||||
/* seek to correct place & remove all leading '/' from component */
|
||||
pcomp = po_comp->po_path;
|
||||
pcomp += offset;
|
||||
while (*pcomp == '/') {
|
||||
pcomp++;
|
||||
complen--;
|
||||
}
|
||||
|
||||
/* todotdot or nottodotdot */
|
||||
if (complen == 2 && strcmp(pcomp, "..") == 0)
|
||||
isdotdot = 1;
|
||||
else
|
||||
isdotdot = 0;
|
||||
|
||||
/*
|
||||
* Strip trailing components from the preceending component.
|
||||
* This is an issue only for the root node, which we might want
|
||||
* to be at path "/" for some file systems.
|
||||
*/
|
||||
prelen = po_pre->po_len;
|
||||
while (prelen > 0 && *((char *)po_pre->po_path + (prelen-1)) == '/') {
|
||||
assert(isdotdot == 0);
|
||||
prelen--;
|
||||
}
|
||||
|
||||
if (isdotdot) {
|
||||
char *slash; /* sweet char of mine */
|
||||
|
||||
slash = strrchr(po_pre->po_path, '/');
|
||||
assert(slash != NULL);
|
||||
|
||||
plen = slash - (char *)po_pre->po_path;
|
||||
|
||||
/*
|
||||
* As the converse to not stripping the initial "/" above,
|
||||
* don't nuke it here either.
|
||||
*/
|
||||
if (plen == 0)
|
||||
plen++;
|
||||
|
||||
path = malloc(plen + 1);
|
||||
if (path == NULL)
|
||||
return errno;
|
||||
|
||||
strlcpy(path, po_pre->po_path, plen+1);
|
||||
} else {
|
||||
/* + '/' + '\0' */
|
||||
plen = prelen + 1 + complen;
|
||||
path = malloc(plen + 1);
|
||||
if (path == NULL)
|
||||
return errno;
|
||||
|
||||
strlcpy(path, po_pre->po_path, prelen+1);
|
||||
strcat(path, "/");
|
||||
strncat(path, pcomp, complen);
|
||||
}
|
||||
|
||||
newpath->po_path = path;
|
||||
newpath->po_len = plen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
puffs_stdpath_freepath(struct puffs_usermount *pu, struct puffs_pathobj *po)
|
||||
{
|
||||
|
||||
free(po->po_path);
|
||||
}
|
||||
|
|
@ -1,216 +0,0 @@
|
|||
/* $NetBSD: pnode.c,v 1.13 2012/08/16 09:25:43 manu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: pnode.c,v 1.13 2012/08/16 09:25:43 manu Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <puffs.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
/*
|
||||
* Well, you're probably wondering why this isn't optimized.
|
||||
* The reason is simple: my available time is not optimized for
|
||||
* size ... so please be patient ;)
|
||||
*/
|
||||
struct puffs_node *
|
||||
puffs_pn_new(struct puffs_usermount *pu, void *privdata)
|
||||
{
|
||||
struct puffs_node *pn;
|
||||
|
||||
pn = calloc(1, sizeof(struct puffs_node));
|
||||
if (pn == NULL)
|
||||
return NULL;
|
||||
|
||||
pn->pn_data = privdata;
|
||||
pn->pn_mnt = pu;
|
||||
puffs_vattr_null(&pn->pn_va);
|
||||
|
||||
LIST_INSERT_HEAD(&pu->pu_pnodelst, pn, pn_entries);
|
||||
|
||||
pu->pu_flags |= PUFFS_FLAG_PNCOOKIE;
|
||||
|
||||
return pn;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_pn_remove(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
LIST_REMOVE(pn, pn_entries);
|
||||
pn->pn_flags |= PUFFS_NODE_REMOVED;
|
||||
#if defined(__minix)
|
||||
if (pn->pn_count != 0) {
|
||||
struct puffs_usermount *pu = pn->pn_mnt;
|
||||
assert(pu != NULL);
|
||||
|
||||
/* XXX FS removes this pn from the list to prevent further
|
||||
* lookups from finding node after remove/rm/rename op.
|
||||
* But VFS still uses it, i.e. pnode is still open, and
|
||||
* will put it later. Keep it in separate list to do reclaim
|
||||
* in fs_put().
|
||||
*/
|
||||
LIST_INSERT_HEAD(&pu->pu_pnode_removed_lst, pn, pn_entries);
|
||||
}
|
||||
#endif /* defined(__minix) */
|
||||
}
|
||||
|
||||
void
|
||||
puffs_pn_put(struct puffs_node *pn)
|
||||
{
|
||||
struct puffs_usermount *pu = pn->pn_mnt;
|
||||
|
||||
pu->pu_pathfree(pu, &pn->pn_po);
|
||||
if ((pn->pn_flags & PUFFS_NODE_REMOVED) == 0)
|
||||
LIST_REMOVE(pn, pn_entries);
|
||||
free(pn);
|
||||
}
|
||||
|
||||
/* walk list, rv can be used either to halt or to return a value */
|
||||
void *
|
||||
puffs_pn_nodewalk(struct puffs_usermount *pu, puffs_nodewalk_fn fn, void *arg)
|
||||
{
|
||||
struct puffs_node *pn_cur, *pn_next;
|
||||
void *rv;
|
||||
|
||||
pn_cur = LIST_FIRST(&pu->pu_pnodelst);
|
||||
while (pn_cur) {
|
||||
pn_next = LIST_NEXT(pn_cur, pn_entries);
|
||||
rv = fn(pu, pn_cur, arg);
|
||||
if (rv)
|
||||
return rv;
|
||||
pn_cur = pn_next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct vattr *
|
||||
puffs_pn_getvap(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
return &pn->pn_va;
|
||||
}
|
||||
|
||||
void *
|
||||
puffs_pn_getpriv(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
return pn->pn_data;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_pn_setpriv(struct puffs_node *pn, void *priv)
|
||||
{
|
||||
|
||||
pn->pn_data = priv;
|
||||
}
|
||||
|
||||
struct puffs_pathobj *
|
||||
puffs_pn_getpo(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
return &pn->pn_po;
|
||||
}
|
||||
|
||||
struct puffs_usermount *
|
||||
puffs_pn_getmnt(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
return pn->pn_mnt;
|
||||
}
|
||||
|
||||
/* convenience / shortcut */
|
||||
void *
|
||||
puffs_pn_getmntspecific(struct puffs_node *pn)
|
||||
{
|
||||
|
||||
return pn->pn_mnt->pu_privdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* newnode parameters
|
||||
*/
|
||||
void
|
||||
puffs_newinfo_setcookie(struct puffs_newinfo *pni, puffs_cookie_t cookie)
|
||||
{
|
||||
|
||||
*pni->pni_cookie = cookie;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setvtype(struct puffs_newinfo *pni, enum vtype vt)
|
||||
{
|
||||
|
||||
*pni->pni_vtype = vt;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setsize(struct puffs_newinfo *pni, voff_t size)
|
||||
{
|
||||
|
||||
*pni->pni_size = size;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setrdev(struct puffs_newinfo *pni, dev_t rdev)
|
||||
{
|
||||
|
||||
*pni->pni_rdev = rdev;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setva(struct puffs_newinfo *pni, struct vattr *va)
|
||||
{
|
||||
|
||||
(void)memcpy(pni->pni_va, va, sizeof(struct vattr));
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setvattl(struct puffs_newinfo *pni, struct timespec *va_ttl)
|
||||
{
|
||||
|
||||
pni->pni_va_ttl->tv_sec = va_ttl->tv_sec;
|
||||
pni->pni_va_ttl->tv_nsec = va_ttl->tv_nsec;
|
||||
}
|
||||
|
||||
void
|
||||
puffs_newinfo_setcnttl(struct puffs_newinfo *pni, struct timespec *cn_ttl)
|
||||
{
|
||||
|
||||
pni->pni_cn_ttl->tv_sec = cn_ttl->tv_sec;
|
||||
pni->pni_cn_ttl->tv_nsec = cn_ttl->tv_nsec;
|
||||
}
|
||||
|
||||
|
|
@ -1,593 +0,0 @@
|
|||
.\" $NetBSD: puffs.3,v 1.61 2015/02/16 10:48:34 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2006, 2007, 2008 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd February 15, 2015
|
||||
.Dt PUFFS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs
|
||||
.Nd Pass-to-Userspace Framework File System development interface
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft struct puffs_usermount *
|
||||
.Fo puffs_init
|
||||
.Fa "struct puffs_ops *pops" "const char *mntfromname" "const char *puffsname"
|
||||
.Fa "void *private" "uint32_t flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_mount
|
||||
.Fa "struct puffs_usermount *pu" "const char *dir" "int mntflags"
|
||||
.Fa "puffs_cookie_t root_cookie"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_getselectable "struct puffs_usermount *pu"
|
||||
.Ft int
|
||||
.Fn puffs_setblockingmode "struct puffs_usermount *pu" "int mode"
|
||||
.Ft int
|
||||
.Fn puffs_getstate "struct puffs_usermount *pu"
|
||||
.Ft int
|
||||
.Fn puffs_setstacksize "struct puffs_usermount *pu" "size_t stacksize"
|
||||
.Ft void
|
||||
.Fn puffs_setroot "struct puffs_usermount *pu" "struct puffs_node *node"
|
||||
.Ft void
|
||||
.Fo puffs_setrootinfo
|
||||
.Fa "struct puffs_usermount *pu" "enum vtype vt" "vsize_t vsize" "dev_t rdev"
|
||||
.Fc
|
||||
.Ft struct puffs_node *
|
||||
.Fn puffs_getroot "struct puffs_usermount *pu"
|
||||
.Ft void *
|
||||
.Fn puffs_getspecific "struct puffs_usermount *pu"
|
||||
.Ft void
|
||||
.Fn puffs_setspecific "struct puffs_usermount *pu" "void *private"
|
||||
.Ft void
|
||||
.Fn puffs_setmaxreqlen "struct puffs_usermount *pu" "size_t maxreqlen"
|
||||
.Ft size_t
|
||||
.Fn puffs_getmaxreqlen "struct puffs_usermount *pu"
|
||||
.Ft void
|
||||
.Fn puffs_setfhsize "struct puffs_usermount *pu" "size_t fhsize" "int flags"
|
||||
.Ft void
|
||||
.Fn puffs_setncookiehash "struct puffs_usermount *pu" "int nhashes"
|
||||
.Ft void
|
||||
.Fn puffs_ml_loop_fn "struct puffs_usermount *pu"
|
||||
.Ft void
|
||||
.Fn puffs_ml_setloopfn "struct puffs_usermount *pu" "puffs_ml_loop_fn lfn"
|
||||
.Ft void
|
||||
.Fn puffs_ml_settimeout "struct puffs_usermount *pu" "struct timespec *ts"
|
||||
.Ft int
|
||||
.Fn puffs_daemon "struct puffs_usermount *pu" "int nochdir" "int noclose"
|
||||
.Ft int
|
||||
.Fn puffs_mainloop "struct puffs_usermount *pu"
|
||||
.Ft int
|
||||
.Fn puffs_unmountonsignal "int sig" "bool ignoresig"
|
||||
.Ft int
|
||||
.Fo puffs_dispatch_create
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pb"
|
||||
.Fa "struct puffs_cc **pccp"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_dispatch_exec "struct puffs_cc *pcc" "struct puffs_framebuf **pbp"
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
provides a framework for creating file systems as userspace servers.
|
||||
Operations are transported from the kernel virtual file system layer
|
||||
to the concrete implementation behind
|
||||
.Nm ,
|
||||
where they are processed and results are sent back to the kernel.
|
||||
.Pp
|
||||
It is possible to use
|
||||
.Nm
|
||||
in two different ways.
|
||||
Calling
|
||||
.Fn puffs_mainloop
|
||||
takes execution context away from the caller and automatically handles
|
||||
all requests by using the callbacks.
|
||||
By using
|
||||
.Xr puffs_framebuf 3
|
||||
in conjuction with
|
||||
.Fn puffs_mainloop ,
|
||||
it is possible to handle I/O to and from file descriptors.
|
||||
This is suited e.g. for distributed file servers.
|
||||
.Ss Library operation
|
||||
Operations on the library always require a pointer to the opaque context
|
||||
identifier,
|
||||
.Va struct puffs_usermount .
|
||||
It is obtained by calling
|
||||
.Fn puffs_init .
|
||||
.Pp
|
||||
.Nm
|
||||
operates using operation callbacks.
|
||||
They can be initialized using the macro
|
||||
.Fn PUFFSOP_SET pops fsname type opname ,
|
||||
which will initialize the operation
|
||||
.Fn puffs_type_opname
|
||||
in
|
||||
.Fa pops
|
||||
to
|
||||
.Fn fsname_type_opname .
|
||||
All operations are initialized to a default state with the call
|
||||
.Fn PUFFSOP_INIT pops .
|
||||
All of the VFS routines are mandatory, but all of the node operations
|
||||
with the exception of
|
||||
.Fn puffs_node_lookup
|
||||
are optional.
|
||||
However, leaving operations blank will naturally have an effect on the
|
||||
features available from the file system implementation.
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_init pops mntfromname puffsname private flags
|
||||
Initializes the library context.
|
||||
.Ar pops
|
||||
specifies the callback operations vector.
|
||||
.Ar mntfromname
|
||||
is device the file system is mounted from.
|
||||
This can be for example a block device such as
|
||||
.Pa /dev/wd0a
|
||||
or, if the file system is pseudo file system, the
|
||||
.Nm
|
||||
device name can be given by
|
||||
.Dv _PATH_PUFFS .
|
||||
This value is used for example in the first column of the output of
|
||||
.Xr mount 8
|
||||
and
|
||||
.Xr df 1 .
|
||||
.Ar puffsname
|
||||
is the file system type.
|
||||
It will always be prepended with the string "puffs|".
|
||||
If possible, file server binaries should be named using the format
|
||||
"mount_myfsnamehere" and this value should equal "myfsnamehere".
|
||||
A file system specific context pointer can optionally be given in
|
||||
.Ar private .
|
||||
This can be retrieved by
|
||||
.Fn puffs_getspecific .
|
||||
Flags for
|
||||
.Nm
|
||||
can be given via
|
||||
.Fa pflags .
|
||||
Currently the following flags are supported:
|
||||
.Bl -tag -width "XPUFFS_KFLAG_LOOKUP_FULLPNBUF"
|
||||
.It Dv PUFFS_KFLAG_NOCACHE_NAME
|
||||
Do not enter pathname components into the name cache.
|
||||
This means that every time the kernel does a lookup for a
|
||||
componentname, the file server will be consulted.
|
||||
.It Dv PUFFS_KFLAG_NOCACHE_PAGE
|
||||
Do not use the page cache.
|
||||
This means that all reads and writes to regular file are
|
||||
propagated to the file server for handling.
|
||||
This option makes a difference only for regular files.
|
||||
.It Dv PUFFS_KFLAG_NOCACHE
|
||||
An alias for both
|
||||
.Dv PUFFS_KFLAG_NOCACHE_NAME
|
||||
and
|
||||
.Dv PUFFS_KFLAG_NOCACHE_PAGE .
|
||||
.It Dv PUFFS_KFLAG_ALLOPS
|
||||
This flag requests that all operations are sent to userspace.
|
||||
Normally the kernel shortcircuits unimplemented operations.
|
||||
This flag is mostly useful for debugging purposes.
|
||||
.It Dv PUFFS_KFLAG_WTCACHE
|
||||
Set the file system cache behavior as write-through.
|
||||
This means that all writes are immediately issued to the file server
|
||||
instead of being flushed in file system sync.
|
||||
This is useful especially for distributed file systems.
|
||||
.It Dv PUFFS_KFLAG_IAONDEMAND
|
||||
Issue inactive only on demand.
|
||||
If a file server defines the inactive method, call it only if the file
|
||||
server has explicitly requested that inactive be called for the
|
||||
node in question.
|
||||
Once inactive has been called for a node, it will not be called
|
||||
again unless the request to call inactive is reissued by the file server.
|
||||
See
|
||||
.Fn puffs_setback
|
||||
in
|
||||
.Xr puffs_ops 3
|
||||
for more information.
|
||||
.It Dv PUFFS_KFLAG_LOOKUP_FULLPNBUF
|
||||
This flag affects only the parameter
|
||||
.Ar pcn to
|
||||
.Fn puffs_node_lookup .
|
||||
If this flag is not given, only the next pathname component under
|
||||
lookup is found from
|
||||
.Ar pcn-\*[Gt]pcn_name .
|
||||
If this flag is given, the full path the kernel was
|
||||
asked to resolve can be found from there.
|
||||
.It Dv PUFFS_FLAG_BUILDPATH
|
||||
The framework will build a complete path name, which is supplied
|
||||
with each operation and can be found from the
|
||||
.Va pcn_po_full.po_path
|
||||
field in a
|
||||
.Vt struct puffs_cn .
|
||||
The option assumes that the framework can map a cookie to a
|
||||
.Vt struct puffs_node .
|
||||
See
|
||||
.Sx Cookies
|
||||
for more information on cookie mapping.
|
||||
See
|
||||
.Xr puffs_path 3
|
||||
for more information on library calls involving paths.
|
||||
.It Dv PUFFS_FLAG_HASHPATH
|
||||
Calculate a hash of the path into the path object field
|
||||
.Va po_hash .
|
||||
This hash value is used by
|
||||
.Fn puffs_path_walkcmp
|
||||
to avoid doing a full comparison for every path equal in length to
|
||||
the one searched for.
|
||||
Especially if the file system uses the abovementioned function, it
|
||||
is a good idea to define this flag.
|
||||
.It Dv PUFFS_FLAG_PNCOOKIE
|
||||
Tell puffs that cookies map to
|
||||
.Vt struct pnode .
|
||||
This is automagically set if
|
||||
.Fn puffs_pn_new
|
||||
is called.
|
||||
.It Dv PUFFS_KFLAG_CACHE_FS_TTL
|
||||
Enforce name and attribute caches based on file system-supplied TTL.
|
||||
In lookup, create, mknod, mkdir, and symlink, the file system must
|
||||
update the node attributes, their TTL, and the node name TTL through
|
||||
.Fn puffs_newinfo_setva ,
|
||||
.Fn puffs_newinfo_setvattl ,
|
||||
and
|
||||
.Fn puffs_newinfo_setcnttl .
|
||||
.Pp
|
||||
Additionally,
|
||||
.Fn puffs_node_getattr_ttl
|
||||
and
|
||||
.Fn puffs_node_setattr_ttl
|
||||
will be called instead of
|
||||
.Fn puffs_node_getattr
|
||||
and
|
||||
.Fn puffs_node_setattr .
|
||||
.It Dv PUFFS_KFLAG_CACHE_DOTDOT
|
||||
Never send lookups for
|
||||
.Dq ..
|
||||
to the file system.
|
||||
Parent vnodes are all kept active until their children are reclaimed.
|
||||
.It Dv PUFFS_KFLAG_NOFLUSH_META
|
||||
Do not send metadata cache flushes for time and size to the file system,
|
||||
which should take care of updating the values on its own.
|
||||
.It Dv PUFFS_FLAG_OPDUMP
|
||||
This option makes the framework dump a textual representation of
|
||||
each operation before executing it.
|
||||
It is useful for debugging purposes.
|
||||
.El
|
||||
.El
|
||||
.Pp
|
||||
The following functions can be used to query or modify the global
|
||||
state of the file system.
|
||||
Note, that all calls are not available at all times.
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_getselectable "pu"
|
||||
Returns a handle to do I/O multiplexing with:
|
||||
.Xr select 2 ,
|
||||
.Xr poll 2 ,
|
||||
and
|
||||
.Xr kqueue 2
|
||||
are all examples of acceptable operations.
|
||||
.It Fn puffs_setblockingmode "pu" "mode"
|
||||
Sets the file system upstream access to blocking or non-blocking mode.
|
||||
Acceptable values for the argument are
|
||||
.Dv PUFFSDEV_BLOCK
|
||||
and
|
||||
.Dv PUFFSDEV_NONBLOCK .
|
||||
.Pp
|
||||
This routine can be called only after calling
|
||||
.Fn puffs_mount .
|
||||
.It Fn puffs_getstate "pu"
|
||||
Returns the state of the file system.
|
||||
It is maintained by the framework and is mostly useful for the framework
|
||||
itself.
|
||||
Possible values are
|
||||
.Dv PUFFS_STATE_BEFOREMOUNT ,
|
||||
.Dv PUFFS_STATE_RUNNING ,
|
||||
.Dv PUFFS_STATE_UNMOUNTING
|
||||
and
|
||||
.Dv PUFFS_STATE_UNMOUNTED .
|
||||
.It Fn puffs_setstacksize "pu" "stacksize"
|
||||
Sets the stack size used when running callbacks.
|
||||
The default is
|
||||
.Dv PUFFS_STACKSIZE_DEFAULT
|
||||
bytes of stack space per request.
|
||||
The minimum stacksize is architecture-dependent and can be specified
|
||||
by using the opaque constant
|
||||
.Dv PUFFS_STACKSIZE_MIN .
|
||||
.It Fn puffs_setroot "pu" "node"
|
||||
Sets the root node of mount
|
||||
.Fa pu
|
||||
to
|
||||
.Fa "node" .
|
||||
Setting the root node is currently required only if the path
|
||||
framework is used, see
|
||||
.Xr puffs_path 3 .
|
||||
.It Fn puffs_setrootinfo pu vt vsize rdev
|
||||
The default root node is a directory.
|
||||
In case the file system wants something different, it can call this
|
||||
function and set the type, size and possible device type to whatever
|
||||
it wants.
|
||||
This routine is independent of
|
||||
.Fn puffs_setroot .
|
||||
.It Fn puffs_getroot "pu"
|
||||
Returns the root node set earlier.
|
||||
.It Fn puffs_getspecific "pu"
|
||||
Returns the
|
||||
.Fa private
|
||||
argument of
|
||||
.Fn puffs_init .
|
||||
.It Fn puffs_setspecific "pu" "private"
|
||||
Can be used to set the specific data after the call to
|
||||
.Fn puffs_init .
|
||||
.It Fn puffs_setmaxreqlen "pu" "maxreqlen"
|
||||
In case the file system desires a maximum buffer length different from
|
||||
the default, the amount
|
||||
.Fa maxreqlen
|
||||
will be requested from the kernel when the file system is mounted.
|
||||
.Pp
|
||||
It is legal to call this function only between
|
||||
.Fn puffs_init
|
||||
and
|
||||
.Fn puffs_mount .
|
||||
.Pp
|
||||
.Em NOTE
|
||||
This does not currently work.
|
||||
.It Fn puffs_getmaxreqlen "pu"
|
||||
Returns the maximum request length the kernel will need for a single
|
||||
request.
|
||||
.Pp
|
||||
.Em NOTE
|
||||
This does not currently work.
|
||||
.It Fn puffs_setfhsize "pu" "fhsize" "flags"
|
||||
Sets the desired file handle size.
|
||||
This must be called if the file system wishes to support NFS exporting
|
||||
file systems of the
|
||||
.Fn fh*
|
||||
family of function calls.
|
||||
.Pp
|
||||
In case all nodes in the file system produce the same length file handle,
|
||||
it must be supplied as
|
||||
.Fa fhsize .
|
||||
In this case, the file system may ignore the length parameters in the
|
||||
file handle callback routines, as the kernel will always pass the
|
||||
correct length buffer.
|
||||
However, if the file handle size varies according to file, the argument
|
||||
.Fa fhsize
|
||||
defines the maximum size of a file handle for the file system.
|
||||
In this case the file system must take care of the handle lengths by
|
||||
itself in the file handle callbacks, see
|
||||
.Xr puffs_ops 3
|
||||
for more information.
|
||||
Also, the flag
|
||||
.Dv PUFFS_FHFLAG_DYNAMIC
|
||||
must be provided in the argument
|
||||
.Fa flags .
|
||||
.Pp
|
||||
In case the file system wants to sanity check its file handle lengths
|
||||
for the limits of NFS, it can supply
|
||||
.Dv PUFFS_FHFLAG_NFSV2
|
||||
and
|
||||
.Dv PUFFS_FHFLAG_NFSV3
|
||||
in the
|
||||
.Fa flags
|
||||
parameter.
|
||||
It is especially important to note that these are not directly the
|
||||
limits specified by the protocols, as the kernel uses some bytes from
|
||||
the buffer space.
|
||||
In case the file handles are too large, mount will return an error.
|
||||
.Pp
|
||||
It is legal to call this function only between
|
||||
.Fn puffs_init
|
||||
and
|
||||
.Fn puffs_mount .
|
||||
.It Fn puffs_setncookiehash "pu" "ncookiehash"
|
||||
The parameter
|
||||
.Fa ncookiehash
|
||||
controls the amount of hash buckets the kernel has for reverse lookups
|
||||
from cookie to vnode.
|
||||
Technically the default is enough, but a memory/time tradeoff can be
|
||||
made by increasing this for file systems which know they will have
|
||||
very many active files.
|
||||
.Pp
|
||||
It is legal to call this function only between
|
||||
.Fn puffs_init
|
||||
and
|
||||
.Fn puffs_mount .
|
||||
.El
|
||||
.Pp
|
||||
After the correct setup for the library has been established and the
|
||||
backend has been initialized the file system is made operational by calling
|
||||
.Fn puffs_mount .
|
||||
After this function returns the file system should start processing requests.
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_mount pu dir mntflags root_cookie
|
||||
.Ar pu
|
||||
is the library context pointer from
|
||||
.Fn puffs_init .
|
||||
The argument
|
||||
.Fa dir
|
||||
signifies the mount point and
|
||||
.Fa mntflags
|
||||
is the flagset given to
|
||||
.Xr mount 2 .
|
||||
The value
|
||||
.Ar root_cookie
|
||||
will be used as the cookie for the file system root node.
|
||||
.El
|
||||
.Ss Using the built-in eventloop
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_ml_loop_fn pu
|
||||
Loop function signature.
|
||||
.It Fn puffs_ml_setloopfn pu lfn
|
||||
Set loop function to
|
||||
.Ar lfn .
|
||||
This function is called once each time the event loop loops.
|
||||
It is not a well-defined interval, but it can be made fairly regular
|
||||
by setting the loop timeout by
|
||||
.Fn puffs_ml_settimeout .
|
||||
.It Fn puffs_ml_settimeout pu ts
|
||||
Sets the loop timeout to
|
||||
.Ar ts
|
||||
or disables it if
|
||||
.Ar ts
|
||||
is
|
||||
.Dv NULL .
|
||||
This can be used to roughly control how often the loop callback
|
||||
.Fn lfn
|
||||
is called
|
||||
.It Fn puffs_daemon pu nochdir noclose
|
||||
Detach from the console like
|
||||
.Fn daemon 3 .
|
||||
This call synchronizes with
|
||||
.Fn puffs_mount
|
||||
and the foreground process does not exit before the file system mount
|
||||
call has returned from the kernel.
|
||||
Since this routine internally calls fork, it has to be called
|
||||
.Em before
|
||||
.Fn puffs_mount .
|
||||
.It Fn puffs_mainloop pu flags
|
||||
Handle all requests automatically until the file system is unmounted.
|
||||
It returns 0 if the file system was successfully unmounted or \-1 if it
|
||||
was killed in action.
|
||||
.Pp
|
||||
In case
|
||||
.Xr puffs_framebuf 3
|
||||
has been initialized, I/O from the relevant descriptors is processed
|
||||
automatically by the eventloop.
|
||||
.It Fn puffs_unmountonsignal signum ignoresig
|
||||
Cause all file servers within the process to initiate unmount upon
|
||||
receipt of signal
|
||||
.Ar signum .
|
||||
This works only for servers which call
|
||||
.Fn puffs_mainloop
|
||||
and must be called before any server within the process enters the mainloop.
|
||||
The process signal handler is still called before starting the unmount
|
||||
procedure.
|
||||
The parameter
|
||||
.Ar ignoresig
|
||||
is provided as a convenience and tells if to install a signal handler
|
||||
to ignore
|
||||
.Ar sig
|
||||
so that the process will not e.g. terminate based on the default action
|
||||
before the file system unmount can be initiated.
|
||||
.It Fn puffs_dispatch_create pu pb pccp
|
||||
.It Fn puffs_dispatch_exec pcc pbp
|
||||
In case the use of
|
||||
.Fn puffs_mainloop
|
||||
is not possible, requests may be dispatched manually.
|
||||
However, as this is less efficient than using the mainloop,
|
||||
it should never be the first preference.
|
||||
.Pp
|
||||
Calling
|
||||
.Fn puffs_dispatch_create
|
||||
creates a dispatch request.
|
||||
The argument
|
||||
.Ar pb
|
||||
should contains a valid request and upon success
|
||||
.Ar pccp
|
||||
will contain a valid request context.
|
||||
This context is passed to
|
||||
.Fn puffs_dispatch_exec
|
||||
to execute the request.
|
||||
If the request yielded before completing, the routine returns 0,
|
||||
otherwise 1.
|
||||
When the routine completes,
|
||||
.Ar pcc
|
||||
is made invalid and a pointer to the processed buffer is placed in
|
||||
.Ar pbp .
|
||||
It is the responsibility of the caller to send the response (if
|
||||
necessary) and destroy the buffer.
|
||||
.Pp
|
||||
See
|
||||
.Xr puffs_cc 3
|
||||
and
|
||||
.Xr puffs_framebuf 3
|
||||
for further information.
|
||||
.El
|
||||
.Ss Cookies
|
||||
Every file (regular file, directory, device node, ...) instance is
|
||||
attached to the kernel using a cookie.
|
||||
A cookie should uniquely map to a file during its lifetime.
|
||||
If file instances are kept in memory, a simple strategy is to use
|
||||
the virtual address of the structure describing the file.
|
||||
The cookie can be recycled when
|
||||
.Fn puffs_node_reclaim
|
||||
is called for a node.
|
||||
.Pp
|
||||
For some operations (such as building paths) the framework needs to map
|
||||
the cookie to the framework-level structure describing a file,
|
||||
.Vt struct puffs_node .
|
||||
It is advisable to simply use the
|
||||
.Vt struct puffs_node
|
||||
address as a cookie and store file system specific data in the private
|
||||
portion of
|
||||
.Vt struct puffs_node .
|
||||
The library assumes this by default.
|
||||
If it is not desirable, the file system implementation can call
|
||||
.Fn puffs_set_cookiemap
|
||||
to provide an alternative cookie-to-node mapping function.
|
||||
.Sh SEE ALSO
|
||||
.Xr mount 2 ,
|
||||
.Xr puffs_cc 3 ,
|
||||
.Xr puffs_cred 3 ,
|
||||
.Xr puffs_flush 3 ,
|
||||
.Xr puffs_framebuf 3 ,
|
||||
.Xr puffs_node 3 ,
|
||||
.Xr puffs_ops 3 ,
|
||||
.Xr puffs_path 3 ,
|
||||
.Xr refuse 3 ,
|
||||
.Xr puffs 4
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%D March 2007
|
||||
.%J Proceedings of AsiaBSDCon 2007
|
||||
.%P pp. 29-42
|
||||
.%T puffs - Pass-to-Userspace Framework File System
|
||||
.Re
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%D September 2007
|
||||
.%I Helsinki University of Technology
|
||||
.%R Tech Report TKK-TKO-B157
|
||||
.%T Using puffs for Implementing Client-Server Distributed File Systems
|
||||
.Re
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%A Alistair Crooks
|
||||
.%D September 2007
|
||||
.%J EuroBSDCon 2007
|
||||
.%T ReFUSE: Userspace FUSE Reimplementation Using puffs
|
||||
.Re
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%D March 2008
|
||||
.%J Proceedings of AsiaBSDCon 2008
|
||||
.%P pp. 55-70
|
||||
.%T Send and Receive of File System Protocols: Userspace Approach With puffs
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
An unsupported experimental version of
|
||||
.Nm
|
||||
first appeared in
|
||||
.Nx 4.0 .
|
||||
A stable version appeared in
|
||||
.Nx 5.0 .
|
||||
.Sh AUTHORS
|
||||
.An Antti Kantee Aq Mt pooka@iki.fi
|
||||
1123
lib/libpuffs/puffs.c
1123
lib/libpuffs/puffs.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,737 +0,0 @@
|
|||
/* $NetBSD: puffs.h,v 1.126 2014/10/31 13:56:04 manu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Google Summer of Code program and the Ulla Tuominen Foundation.
|
||||
* The Google SoC project was mentored by Bill Studenmund.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PUFFS_H_
|
||||
#define _PUFFS_H_
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <fs/puffs/puffs_msgif.h>
|
||||
|
||||
#include <mntopts.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
/* forwards */
|
||||
struct puffs_cc;
|
||||
|
||||
struct puffs_getreq;
|
||||
struct puffs_cred;
|
||||
struct puffs_newinfo;
|
||||
|
||||
/* paths */
|
||||
struct puffs_pathobj {
|
||||
void *po_path;
|
||||
size_t po_len;
|
||||
uint32_t po_hash;
|
||||
};
|
||||
|
||||
/* for prefix rename */
|
||||
struct puffs_pathinfo {
|
||||
struct puffs_pathobj *pi_old;
|
||||
struct puffs_pathobj *pi_new;
|
||||
};
|
||||
|
||||
/* describes one segment cached in the kernel */
|
||||
struct puffs_kcache {
|
||||
off_t pkc_start;
|
||||
off_t pkc_end;
|
||||
|
||||
LIST_ENTRY(puffs_kcache) pkc_entries;
|
||||
};
|
||||
|
||||
/* XXX: might disappear from here into a private header */
|
||||
struct puffs_node {
|
||||
off_t pn_size;
|
||||
int pn_flags;
|
||||
int pn_nlookup;
|
||||
struct vattr pn_va;
|
||||
|
||||
void *pn_data; /* private data */
|
||||
|
||||
struct puffs_pathobj pn_po; /* PUFFS_FLAG_BUILDPATH */
|
||||
|
||||
struct puffs_usermount *pn_mnt;
|
||||
LIST_ENTRY(puffs_node) pn_entries;
|
||||
|
||||
LIST_HEAD(,puffs_kcache)pn_cacheinfo; /* PUFFS_KFLAG_CACHE */
|
||||
#if defined(__minix)
|
||||
/* MINIX fields */
|
||||
char pn_mountpoint; /* true if mounted on */
|
||||
unsigned int pn_count; /* # times inode used */
|
||||
#endif /* defined(__minix) */
|
||||
};
|
||||
#define PUFFS_NODE_REMOVED 0x01 /* not on entry list */
|
||||
|
||||
|
||||
struct puffs_usermount;
|
||||
|
||||
/*
|
||||
* megaXXX: these are values from inside _KERNEL
|
||||
* need to work on the translation for ALL the necessary values.
|
||||
*/
|
||||
#define PUFFS_VNOVAL (-1)
|
||||
|
||||
#define PUFFS_IO_APPEND 0x020
|
||||
#define PUFFS_IO_NDELAY 0x100
|
||||
|
||||
#define PUFFS_VEXEC 01
|
||||
#define PUFFS_VWRITE 02
|
||||
#define PUFFS_VREAD 04
|
||||
|
||||
#define PUFFS_FSYNC_DATAONLY 0x0002
|
||||
#define PUFFS_FSYNC_CACHE 0x0100
|
||||
|
||||
/*
|
||||
* xflags for setattr_ttl and write2
|
||||
*/
|
||||
#define PUFFS_SETATTR_FAF 0x1
|
||||
#define PUFFS_WRITE_FAF 0x1
|
||||
|
||||
#define PUFFS_EXTATTR_LIST_LENPREFIX 1
|
||||
/*
|
||||
* Magic constants
|
||||
*/
|
||||
#define PUFFS_CC_STACKSHIFT_DEFAULT 18
|
||||
|
||||
struct puffs_cn {
|
||||
struct puffs_kcn *pcn_pkcnp; /* kernel input */
|
||||
struct puffs_cred *pcn_cred; /* cred used for lookup */
|
||||
|
||||
struct puffs_pathobj pcn_po_full; /* PUFFS_FLAG_BUILDPATH */
|
||||
};
|
||||
#define pcn_nameiop pcn_pkcnp->pkcn_nameiop
|
||||
#define pcn_flags pcn_pkcnp->pkcn_flags
|
||||
#define pcn_name pcn_pkcnp->pkcn_name
|
||||
#define pcn_namelen pcn_pkcnp->pkcn_namelen
|
||||
#define pcn_consume pcn_pkcnp->pkcn_consume
|
||||
|
||||
/*
|
||||
* Puffs options to mount
|
||||
*/
|
||||
/* kernel */
|
||||
#define PUFFSMOPT_NAMECACHE { "namecache", 1, PUFFS_KFLAG_NOCACHE_NAME, 1 }
|
||||
#define PUFFSMOPT_PAGECACHE { "pagecache", 1, PUFFS_KFLAG_NOCACHE_PAGE, 1 }
|
||||
#define PUFFSMOPT_ATTRCACHE { "attrcache", 1, PUFFS_KFLAG_NOCACHE_ATTR, 1 }
|
||||
#define PUFFSMOPT_CACHE { "cache", 1, PUFFS_KFLAG_NOCACHE, 1 }
|
||||
#define PUFFSMOPT_ALLOPS { "allops", 0, PUFFS_KFLAG_ALLOPS, 1 }
|
||||
|
||||
/* libpuffs */
|
||||
#define PUFFSMOPT_DUMP { "dump", 0, PUFFS_FLAG_OPDUMP, 1 }
|
||||
|
||||
#define PUFFSMOPT_STD \
|
||||
PUFFSMOPT_NAMECACHE, \
|
||||
PUFFSMOPT_PAGECACHE, \
|
||||
PUFFSMOPT_ATTRCACHE, \
|
||||
PUFFSMOPT_CACHE, \
|
||||
PUFFSMOPT_ALLOPS, \
|
||||
PUFFSMOPT_DUMP
|
||||
|
||||
extern const struct mntopt puffsmopts[]; /* puffs.c */
|
||||
|
||||
/* callbacks for operations */
|
||||
struct puffs_ops {
|
||||
int (*puffs_fs_unmount)(struct puffs_usermount *, int);
|
||||
int (*puffs_fs_statvfs)(struct puffs_usermount *, struct statvfs *);
|
||||
int (*puffs_fs_sync)(struct puffs_usermount *, int,
|
||||
const struct puffs_cred *);
|
||||
int (*puffs_fs_fhtonode)(struct puffs_usermount *, void *, size_t,
|
||||
struct puffs_newinfo *);
|
||||
int (*puffs_fs_nodetofh)(struct puffs_usermount *, puffs_cookie_t,
|
||||
void *, size_t *);
|
||||
int (*puffs_fs_extattrctl)(struct puffs_usermount *, int,
|
||||
puffs_cookie_t, int, int, const char *);
|
||||
|
||||
int (*puffs_node_lookup)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *);
|
||||
int (*puffs_node_create)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
|
||||
const struct vattr *);
|
||||
int (*puffs_node_mknod)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
|
||||
const struct vattr *);
|
||||
int (*puffs_node_open)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, const struct puffs_cred *);
|
||||
int (*puffs_node_close)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, const struct puffs_cred *);
|
||||
int (*puffs_node_access)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, const struct puffs_cred *);
|
||||
int (*puffs_node_getattr)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *);
|
||||
int (*puffs_node_setattr)(struct puffs_usermount *,
|
||||
puffs_cookie_t, const struct vattr *, const struct puffs_cred *);
|
||||
int (*puffs_node_poll)(struct puffs_usermount *, puffs_cookie_t, int *);
|
||||
int (*puffs_node_mmap)(struct puffs_usermount *,
|
||||
puffs_cookie_t, vm_prot_t, const struct puffs_cred *);
|
||||
int (*puffs_node_fsync)(struct puffs_usermount *,
|
||||
puffs_cookie_t, const struct puffs_cred *, int, off_t, off_t);
|
||||
int (*puffs_node_seek)(struct puffs_usermount *,
|
||||
puffs_cookie_t, off_t, off_t, const struct puffs_cred *);
|
||||
int (*puffs_node_remove)(struct puffs_usermount *,
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
|
||||
int (*puffs_node_link)(struct puffs_usermount *,
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
|
||||
int (*puffs_node_rename)(struct puffs_usermount *,
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *,
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
|
||||
int (*puffs_node_mkdir)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
|
||||
const struct vattr *);
|
||||
int (*puffs_node_rmdir)(struct puffs_usermount *,
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
|
||||
int (*puffs_node_symlink)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
|
||||
const struct vattr *,
|
||||
const char *);
|
||||
int (*puffs_node_readdir)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct dirent *, off_t *, size_t *,
|
||||
const struct puffs_cred *, int *, off_t *, size_t *);
|
||||
int (*puffs_node_readlink)(struct puffs_usermount *,
|
||||
puffs_cookie_t, const struct puffs_cred *, char *, size_t *);
|
||||
int (*puffs_node_reclaim)(struct puffs_usermount *, puffs_cookie_t);
|
||||
int (*puffs_node_inactive)(struct puffs_usermount *, puffs_cookie_t);
|
||||
int (*puffs_node_print)(struct puffs_usermount *, puffs_cookie_t);
|
||||
int (*puffs_node_pathconf)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, register_t *);
|
||||
int (*puffs_node_advlock)(struct puffs_usermount *,
|
||||
puffs_cookie_t, void *, int, struct flock *, int);
|
||||
int (*puffs_node_read)(struct puffs_usermount *, puffs_cookie_t,
|
||||
uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
|
||||
int (*puffs_node_write)(struct puffs_usermount *, puffs_cookie_t,
|
||||
uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
|
||||
int (*puffs_node_abortop)(struct puffs_usermount *, puffs_cookie_t,
|
||||
const struct puffs_cn *);
|
||||
int (*puffs_node_getextattr)(struct puffs_usermount *, puffs_cookie_t,
|
||||
int, const char *, size_t *, uint8_t *, size_t *,
|
||||
const struct puffs_cred *);
|
||||
int (*puffs_node_setextattr)(struct puffs_usermount *, puffs_cookie_t,
|
||||
int, const char *, uint8_t *, size_t *, const struct puffs_cred *);
|
||||
int (*puffs_node_listextattr)(struct puffs_usermount *, puffs_cookie_t,
|
||||
int, size_t *, uint8_t *, size_t *, int, const struct puffs_cred *);
|
||||
int (*puffs_node_deleteextattr)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, const char *, const struct puffs_cred *);
|
||||
int (*puffs_node_getattr_ttl)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *,
|
||||
struct timespec *);
|
||||
int (*puffs_node_setattr_ttl)(struct puffs_usermount *,
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *,
|
||||
struct timespec *, int);
|
||||
int (*puffs_node_write2)(struct puffs_usermount *, puffs_cookie_t,
|
||||
uint8_t *, off_t, size_t *, const struct puffs_cred *, int, int);
|
||||
int (*puffs_node_reclaim2)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int);
|
||||
int (*puffs_node_open2)(struct puffs_usermount *,
|
||||
puffs_cookie_t, int, const struct puffs_cred *, int *);
|
||||
int (*puffs_node_fallocate)(struct puffs_usermount *,
|
||||
puffs_cookie_t, off_t, off_t);
|
||||
int (*puffs_node_fdiscard)(struct puffs_usermount *,
|
||||
puffs_cookie_t, off_t, off_t);
|
||||
|
||||
void *puffs_ops_spare[26];
|
||||
};
|
||||
|
||||
typedef int (*pu_pathbuild_fn)(struct puffs_usermount *,
|
||||
const struct puffs_pathobj *,
|
||||
const struct puffs_pathobj *, size_t,
|
||||
struct puffs_pathobj *);
|
||||
typedef int (*pu_pathtransform_fn)(struct puffs_usermount *,
|
||||
const struct puffs_pathobj *,
|
||||
const struct puffs_cn *,
|
||||
struct puffs_pathobj *);
|
||||
typedef int (*pu_pathcmp_fn)(struct puffs_usermount *, struct puffs_pathobj *,
|
||||
struct puffs_pathobj *, size_t, int);
|
||||
typedef void (*pu_pathfree_fn)(struct puffs_usermount *,
|
||||
struct puffs_pathobj *);
|
||||
typedef int (*pu_namemod_fn)(struct puffs_usermount *,
|
||||
struct puffs_pathobj *, struct puffs_cn *);
|
||||
|
||||
typedef void (*pu_errnotify_fn)(struct puffs_usermount *,
|
||||
uint8_t, int, const char *, puffs_cookie_t);
|
||||
|
||||
typedef void (*pu_prepost_fn)(struct puffs_usermount *);
|
||||
|
||||
typedef struct puffs_node *(*pu_cmap_fn)(struct puffs_usermount *,
|
||||
puffs_cookie_t);
|
||||
|
||||
enum {
|
||||
PUFFS_STATE_BEFOREMOUNT, PUFFS_STATE_RUNNING,
|
||||
PUFFS_STATE_UNMOUNTING, PUFFS_STATE_UNMOUNTED
|
||||
};
|
||||
|
||||
#define PUFFS_FLAG_BUILDPATH 0x80000000 /* node paths in pnode */
|
||||
#define PUFFS_FLAG_OPDUMP 0x40000000 /* dump all operations */
|
||||
#define PUFFS_FLAG_HASHPATH 0x20000000 /* speedup: hash paths */
|
||||
#define PUFFS_FLAG_PNCOOKIE 0x10000000 /* cookies are pnodes */
|
||||
#define PUFFS_FLAG_MASK 0xf0000000
|
||||
|
||||
#define PUFFS_FLAG_KERN(a) ((a) & PUFFS_KFLAG_MASK)
|
||||
#define PUFFS_FLAG_LIB(a) ((a) & PUFFS_FLAG_MASK)
|
||||
|
||||
/* blocking mode argument */
|
||||
#define PUFFSDEV_BLOCK 0
|
||||
#define PUFFSDEV_NONBLOCK 1
|
||||
|
||||
#define PUFFS_STACKSIZE_DEFAULT (1<<PUFFS_CC_STACKSHIFT_DEFAULT)
|
||||
#define PUFFS_STACKSIZE_MIN ((size_t)-1)
|
||||
|
||||
#define DENT_DOT 0
|
||||
#define DENT_DOTDOT 1
|
||||
#define DENT_ADJ(a) ((a)-2) /* nth request means dir's n-2th */
|
||||
|
||||
|
||||
/*
|
||||
* protos
|
||||
*/
|
||||
|
||||
#define PUFFSOP_PROTOS(fsname) \
|
||||
int fsname##_fs_unmount(struct puffs_usermount *, int); \
|
||||
int fsname##_fs_statvfs(struct puffs_usermount *, \
|
||||
struct statvfs *); \
|
||||
int fsname##_fs_sync(struct puffs_usermount *, int, \
|
||||
const struct puffs_cred *cred); \
|
||||
int fsname##_fs_fhtonode(struct puffs_usermount *, void *, \
|
||||
size_t, struct puffs_newinfo *); \
|
||||
int fsname##_fs_nodetofh(struct puffs_usermount *, \
|
||||
puffs_cookie_t, void *, size_t *); \
|
||||
int fsname##_fs_extattrctl(struct puffs_usermount *, int, \
|
||||
puffs_cookie_t, int, int, const char *); \
|
||||
\
|
||||
int fsname##_node_lookup(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct puffs_newinfo *, \
|
||||
const struct puffs_cn *); \
|
||||
int fsname##_node_create(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct puffs_newinfo *, \
|
||||
const struct puffs_cn *, const struct vattr *); \
|
||||
int fsname##_node_mknod(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct puffs_newinfo *, \
|
||||
const struct puffs_cn *, const struct vattr *); \
|
||||
int fsname##_node_open(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const struct puffs_cred *); \
|
||||
int fsname##_node_close(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const struct puffs_cred *); \
|
||||
int fsname##_node_access(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const struct puffs_cred *); \
|
||||
int fsname##_node_getattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *); \
|
||||
int fsname##_node_setattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, const struct vattr *, \
|
||||
const struct puffs_cred *); \
|
||||
int fsname##_node_poll(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int *); \
|
||||
int fsname##_node_mmap(struct puffs_usermount *, \
|
||||
puffs_cookie_t, vm_prot_t, const struct puffs_cred *); \
|
||||
int fsname##_node_fsync(struct puffs_usermount *, \
|
||||
puffs_cookie_t, const struct puffs_cred *, int, \
|
||||
off_t, off_t); \
|
||||
int fsname##_node_seek(struct puffs_usermount *, \
|
||||
puffs_cookie_t, off_t, off_t, const struct puffs_cred *); \
|
||||
int fsname##_node_remove(struct puffs_usermount *, \
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); \
|
||||
int fsname##_node_link(struct puffs_usermount *, \
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); \
|
||||
int fsname##_node_rename(struct puffs_usermount *, \
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *, \
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); \
|
||||
int fsname##_node_mkdir(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct puffs_newinfo *, \
|
||||
const struct puffs_cn *, const struct vattr *); \
|
||||
int fsname##_node_rmdir(struct puffs_usermount *, \
|
||||
puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); \
|
||||
int fsname##_node_symlink(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct puffs_newinfo *, \
|
||||
const struct puffs_cn *, const struct vattr *, \
|
||||
const char *); \
|
||||
int fsname##_node_readdir(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct dirent *, off_t *, size_t *, \
|
||||
const struct puffs_cred *, int *, off_t *, size_t *); \
|
||||
int fsname##_node_readlink(struct puffs_usermount *, \
|
||||
puffs_cookie_t, const struct puffs_cred *, char *, \
|
||||
size_t *); \
|
||||
int fsname##_node_reclaim(struct puffs_usermount *, \
|
||||
puffs_cookie_t); \
|
||||
int fsname##_node_inactive(struct puffs_usermount *, \
|
||||
puffs_cookie_t); \
|
||||
int fsname##_node_print(struct puffs_usermount *, \
|
||||
puffs_cookie_t); \
|
||||
int fsname##_node_pathconf(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, register_t *); \
|
||||
int fsname##_node_advlock(struct puffs_usermount *, \
|
||||
puffs_cookie_t, void *, int, struct flock *, int); \
|
||||
int fsname##_node_read(struct puffs_usermount *, puffs_cookie_t,\
|
||||
uint8_t *, off_t, size_t *, const struct puffs_cred *, int);\
|
||||
int fsname##_node_write(struct puffs_usermount *, \
|
||||
puffs_cookie_t, uint8_t *, off_t, size_t *, \
|
||||
const struct puffs_cred *, int); \
|
||||
int fsname##_node_abortop(struct puffs_usermount *, \
|
||||
puffs_cookie_t, const struct puffs_cn *); \
|
||||
int fsname##_node_getextattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const char *, size_t *, uint8_t *, \
|
||||
size_t *, const struct puffs_cred *); \
|
||||
int fsname##_node_setextattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const char *, uint8_t *, size_t *, \
|
||||
const struct puffs_cred *); \
|
||||
int fsname##_node_listextattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, size_t *, uint8_t *, size_t *, \
|
||||
int, const struct puffs_cred *); \
|
||||
int fsname##_node_deleteextattr(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const char *, \
|
||||
const struct puffs_cred *); \
|
||||
int fsname##_node_getattr_ttl(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *, \
|
||||
struct timespec *); \
|
||||
int fsname##_node_setattr_ttl(struct puffs_usermount *, \
|
||||
puffs_cookie_t, struct vattr *, const struct puffs_cred *, \
|
||||
struct timespec *, int); \
|
||||
int fsname##_node_write2(struct puffs_usermount *, \
|
||||
puffs_cookie_t, uint8_t *, off_t, size_t *, \
|
||||
const struct puffs_cred *, int, int); \
|
||||
int fsname##_node_reclaim2(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int); \
|
||||
int fsname##_node_open2(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, const struct puffs_cred *, int *); \
|
||||
int fsname##_node_fallocate(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, off_t, off_t); \
|
||||
int fsname##_node_fdiscard(struct puffs_usermount *, \
|
||||
puffs_cookie_t, int, off_t, off_t);
|
||||
|
||||
|
||||
#define PUFFSOP_INIT(ops) \
|
||||
ops = malloc(sizeof(struct puffs_ops)); \
|
||||
memset(ops, 0, sizeof(struct puffs_ops))
|
||||
#define PUFFSOP_SET(ops, fsname, fsornode, opname) \
|
||||
(ops)->puffs_##fsornode##_##opname = fsname##_##fsornode##_##opname
|
||||
#define PUFFSOP_SETFSNOP(ops, opname) \
|
||||
(ops)->puffs_fs_##opname = puffs_fsnop_##opname
|
||||
|
||||
PUFFSOP_PROTOS(puffs_null) /* XXX */
|
||||
|
||||
#define PNPATH(pnode) ((pnode)->pn_po.po_path)
|
||||
#define PNPLEN(pnode) ((pnode)->pn_po.po_len)
|
||||
#define PCNPATH(pcnode) ((pcnode)->pcn_po_full.po_path)
|
||||
#define PCNPLEN(pcnode) ((pcnode)->pcn_po_full.po_len)
|
||||
#define PCNISDOTDOT(pcnode) \
|
||||
((pcnode)->pcn_namelen == 2 && strcmp((pcnode)->pcn_name, "..") == 0)
|
||||
|
||||
#define PUFFS_STORE_DCOOKIE(cp, ncp, off) \
|
||||
if (cp) { \
|
||||
*((cp)++) = off; \
|
||||
(*(ncp))++; \
|
||||
}
|
||||
|
||||
/* mainloop */
|
||||
typedef void (*puffs_ml_loop_fn)(struct puffs_usermount *);
|
||||
|
||||
/* framebuf stuff */
|
||||
struct puffs_framebuf;
|
||||
typedef int (*puffs_framev_readframe_fn)(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
int, int *);
|
||||
typedef int (*puffs_framev_writeframe_fn)(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
int, int *);
|
||||
typedef int (*puffs_framev_cmpframe_fn)(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
struct puffs_framebuf *,
|
||||
int *);
|
||||
typedef void (*puffs_framev_fdnotify_fn)(struct puffs_usermount *, int, int);
|
||||
typedef void (*puffs_framev_gotframe_fn)(struct puffs_usermount *,
|
||||
struct puffs_framebuf *);
|
||||
typedef void (*puffs_framev_cb)(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
void *, int);
|
||||
#define PUFFS_FBIO_READ 0x01
|
||||
#define PUFFS_FBIO_WRITE 0x02
|
||||
#define PUFFS_FBIO_ERROR 0x04
|
||||
|
||||
#define PUFFS_FBQUEUE_URGENT 0x01
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define PUFFS_DEFER ((void *)-1)
|
||||
struct puffs_usermount *puffs_init(struct puffs_ops *, const char *,
|
||||
const char *, void *, uint32_t);
|
||||
int puffs_mount(struct puffs_usermount *, const char *, int, void*);
|
||||
int puffs_exit(struct puffs_usermount *, int);
|
||||
void puffs_cancel(struct puffs_usermount *, int);
|
||||
int puffs_mainloop(struct puffs_usermount *);
|
||||
int puffs_daemon(struct puffs_usermount *, int, int);
|
||||
|
||||
int puffs_unmountonsignal(int, bool);
|
||||
|
||||
|
||||
int puffs_getselectable(struct puffs_usermount *);
|
||||
int puffs_setblockingmode(struct puffs_usermount *, int);
|
||||
int puffs_getstate(struct puffs_usermount *);
|
||||
void puffs_setstacksize(struct puffs_usermount *, size_t);
|
||||
|
||||
void puffs_ml_setloopfn(struct puffs_usermount *, puffs_ml_loop_fn);
|
||||
void puffs_ml_settimeout(struct puffs_usermount *, struct timespec *);
|
||||
|
||||
void puffs_setroot(struct puffs_usermount *,
|
||||
struct puffs_node *);
|
||||
struct puffs_node *puffs_getroot(struct puffs_usermount *);
|
||||
void puffs_setrootinfo(struct puffs_usermount *,
|
||||
enum vtype, vsize_t, dev_t);
|
||||
|
||||
void *puffs_getspecific(struct puffs_usermount *);
|
||||
void puffs_setspecific(struct puffs_usermount *, void *);
|
||||
void puffs_setmaxreqlen(struct puffs_usermount *, size_t);
|
||||
size_t puffs_getmaxreqlen(struct puffs_usermount *);
|
||||
void puffs_setfhsize(struct puffs_usermount *, size_t, int);
|
||||
void puffs_setmntinfo(struct puffs_usermount *,
|
||||
const char *, const char *);
|
||||
|
||||
void puffs_setncookiehash(struct puffs_usermount *, int);
|
||||
|
||||
struct puffs_pathobj *puffs_getrootpathobj(struct puffs_usermount *);
|
||||
|
||||
void puffs_setback(struct puffs_cc *, int);
|
||||
|
||||
struct puffs_node *puffs_pn_new(struct puffs_usermount *, void *);
|
||||
void puffs_pn_remove(struct puffs_node *);
|
||||
void puffs_pn_put(struct puffs_node *);
|
||||
struct vattr *puffs_pn_getvap(struct puffs_node *);
|
||||
void * puffs_pn_getpriv(struct puffs_node *);
|
||||
void puffs_pn_setpriv(struct puffs_node *, void *);
|
||||
struct puffs_pathobj *puffs_pn_getpo(struct puffs_node *);
|
||||
struct puffs_usermount *puffs_pn_getmnt(struct puffs_node *);
|
||||
struct timespec *puffs_pn_getvattl(struct puffs_node *);
|
||||
struct timespec *puffs_pn_getcnttl(struct puffs_node *);
|
||||
|
||||
void puffs_newinfo_setcookie(struct puffs_newinfo *, puffs_cookie_t);
|
||||
void puffs_newinfo_setvtype(struct puffs_newinfo *, enum vtype);
|
||||
void puffs_newinfo_setsize(struct puffs_newinfo *, voff_t);
|
||||
void puffs_newinfo_setrdev(struct puffs_newinfo *, dev_t);
|
||||
void puffs_newinfo_setva(struct puffs_newinfo *, struct vattr *);
|
||||
void puffs_newinfo_setvattl(struct puffs_newinfo *, struct timespec *);
|
||||
void puffs_newinfo_setcnttl(struct puffs_newinfo *, struct timespec *);
|
||||
|
||||
void *puffs_pn_getmntspecific(struct puffs_node *);
|
||||
|
||||
typedef void * (*puffs_nodewalk_fn)(struct puffs_usermount *,
|
||||
struct puffs_node *, void *);
|
||||
void *puffs_pn_nodewalk(struct puffs_usermount *,
|
||||
puffs_nodewalk_fn, void *);
|
||||
|
||||
void puffs_setvattr(struct vattr *, const struct vattr *);
|
||||
void puffs_vattr_null(struct vattr *);
|
||||
|
||||
void puffs_null_setops(struct puffs_ops *);
|
||||
|
||||
int puffs_dispatch_create(struct puffs_usermount *,
|
||||
struct puffs_framebuf *,
|
||||
struct puffs_cc **);
|
||||
int puffs_dispatch_exec(struct puffs_cc *,
|
||||
struct puffs_framebuf **);
|
||||
|
||||
/*
|
||||
* generic/dummy routines applicable for some file systems
|
||||
*/
|
||||
int puffs_fsnop_unmount(struct puffs_usermount *, int);
|
||||
int puffs_fsnop_statvfs(struct puffs_usermount *, struct statvfs *);
|
||||
void puffs_zerostatvfs(struct statvfs *);
|
||||
int puffs_fsnop_sync(struct puffs_usermount *, int waitfor,
|
||||
const struct puffs_cred *);
|
||||
|
||||
int puffs_genfs_node_getattr(struct puffs_usermount *, puffs_cookie_t,
|
||||
struct vattr *, const struct puffs_cred *);
|
||||
int puffs_genfs_node_reclaim(struct puffs_usermount *, puffs_cookie_t);
|
||||
|
||||
/*
|
||||
* Subroutine stuff
|
||||
*/
|
||||
|
||||
int puffs_gendotdent(struct dirent **, ino_t, int, size_t *);
|
||||
int puffs_nextdent(struct dirent **, const char *, ino_t,
|
||||
uint8_t, size_t *);
|
||||
int puffs_vtype2dt(enum vtype);
|
||||
enum vtype puffs_mode2vt(mode_t);
|
||||
void puffs_stat2vattr(struct vattr *va, const struct stat *);
|
||||
mode_t puffs_addvtype2mode(mode_t, enum vtype);
|
||||
|
||||
|
||||
/*
|
||||
* credentials & permissions
|
||||
*/
|
||||
|
||||
/* Credential fetch */
|
||||
int puffs_cred_getuid(const struct puffs_cred *, uid_t *);
|
||||
int puffs_cred_getgid(const struct puffs_cred *, gid_t *);
|
||||
int puffs_cred_getgroups(const struct puffs_cred *, gid_t *, short *);
|
||||
|
||||
/* Credential check */
|
||||
bool puffs_cred_isuid(const struct puffs_cred *, uid_t);
|
||||
bool puffs_cred_hasgroup(const struct puffs_cred *, gid_t);
|
||||
bool puffs_cred_isregular(const struct puffs_cred *);
|
||||
bool puffs_cred_iskernel(const struct puffs_cred *);
|
||||
bool puffs_cred_isfs(const struct puffs_cred *);
|
||||
bool puffs_cred_isjuggernaut(const struct puffs_cred *);
|
||||
|
||||
/* misc */
|
||||
int puffs_access(enum vtype, mode_t, uid_t, gid_t, mode_t,
|
||||
const struct puffs_cred *);
|
||||
int puffs_access_chown(uid_t, gid_t, uid_t, gid_t,
|
||||
const struct puffs_cred *);
|
||||
int puffs_access_chmod(uid_t, gid_t, enum vtype, mode_t,
|
||||
const struct puffs_cred *);
|
||||
int puffs_access_times(uid_t, gid_t, mode_t, int,
|
||||
const struct puffs_cred *);
|
||||
|
||||
|
||||
/*
|
||||
* Call Context interfaces relevant for user.
|
||||
*/
|
||||
|
||||
void puffs_cc_yield(struct puffs_cc *);
|
||||
void puffs_cc_continue(struct puffs_cc *);
|
||||
void puffs_cc_schedule(struct puffs_cc *);
|
||||
int puffs_cc_getcaller(struct puffs_cc *,pid_t *,lwpid_t *);
|
||||
struct puffs_cc *puffs_cc_getcc(struct puffs_usermount *);
|
||||
|
||||
/*
|
||||
* Flushing / invalidation routines
|
||||
*/
|
||||
|
||||
int puffs_inval_namecache_dir(struct puffs_usermount *, puffs_cookie_t);
|
||||
int puffs_inval_namecache_all(struct puffs_usermount *);
|
||||
|
||||
int puffs_inval_pagecache_node(struct puffs_usermount *, puffs_cookie_t);
|
||||
int puffs_inval_pagecache_node_range(struct puffs_usermount *,
|
||||
puffs_cookie_t, off_t, off_t);
|
||||
int puffs_flush_pagecache_node(struct puffs_usermount *, puffs_cookie_t);
|
||||
int puffs_flush_pagecache_node_range(struct puffs_usermount *,
|
||||
puffs_cookie_t, off_t, off_t);
|
||||
|
||||
/*
|
||||
* Path constructicons
|
||||
*/
|
||||
|
||||
int puffs_stdpath_buildpath(struct puffs_usermount *,
|
||||
const struct puffs_pathobj *,
|
||||
const struct puffs_pathobj *, size_t,
|
||||
struct puffs_pathobj *);
|
||||
int puffs_stdpath_cmppath(struct puffs_usermount *, struct puffs_pathobj *,
|
||||
struct puffs_pathobj *, size_t, int);
|
||||
void puffs_stdpath_freepath(struct puffs_usermount *,struct puffs_pathobj *);
|
||||
|
||||
void *puffs_path_walkcmp(struct puffs_usermount *,
|
||||
struct puffs_node *, void *);
|
||||
void *puffs_path_prefixadj(struct puffs_usermount *,
|
||||
struct puffs_node *, void *);
|
||||
int puffs_path_pcnbuild(struct puffs_usermount *,
|
||||
struct puffs_cn *, void *);
|
||||
void puffs_path_buildhash(struct puffs_usermount *, struct puffs_pathobj *);
|
||||
void puffs_set_pathbuild(struct puffs_usermount *, pu_pathbuild_fn); void puffs_set_pathtransform(struct puffs_usermount *, pu_pathtransform_fn);
|
||||
void puffs_set_pathcmp(struct puffs_usermount *, pu_pathcmp_fn);
|
||||
void puffs_set_pathfree(struct puffs_usermount *, pu_pathfree_fn);
|
||||
void puffs_set_namemod(struct puffs_usermount *, pu_namemod_fn);
|
||||
|
||||
void puffs_set_errnotify(struct puffs_usermount *, pu_errnotify_fn);
|
||||
void puffs_kernerr_log(struct puffs_usermount *, uint8_t, int,
|
||||
const char *, puffs_cookie_t);
|
||||
__dead void puffs_kernerr_abort(struct puffs_usermount *, uint8_t, int,
|
||||
const char *, puffs_cookie_t);
|
||||
void puffs_set_prepost(struct puffs_usermount *,
|
||||
pu_prepost_fn, pu_prepost_fn);
|
||||
void puffs_set_cmap(struct puffs_usermount *, pu_cmap_fn);
|
||||
|
||||
/*
|
||||
* Suspension
|
||||
*/
|
||||
|
||||
int puffs_fs_suspend(struct puffs_usermount *);
|
||||
|
||||
/*
|
||||
* Frame buffering
|
||||
*/
|
||||
|
||||
void puffs_framev_init(struct puffs_usermount *,
|
||||
puffs_framev_readframe_fn,
|
||||
puffs_framev_writeframe_fn,
|
||||
puffs_framev_cmpframe_fn,
|
||||
puffs_framev_gotframe_fn,
|
||||
puffs_framev_fdnotify_fn);
|
||||
|
||||
struct puffs_framebuf *puffs_framebuf_make(void);
|
||||
void puffs_framebuf_destroy(struct puffs_framebuf *);
|
||||
int puffs_framebuf_dup(struct puffs_framebuf *,
|
||||
struct puffs_framebuf **);
|
||||
void puffs_framebuf_recycle(struct puffs_framebuf *);
|
||||
int puffs_framebuf_reserve_space(struct puffs_framebuf *,
|
||||
size_t);
|
||||
|
||||
int puffs_framebuf_putdata(struct puffs_framebuf *, const void *, size_t);
|
||||
int puffs_framebuf_putdata_atoff(struct puffs_framebuf *, size_t,
|
||||
const void *, size_t);
|
||||
int puffs_framebuf_getdata(struct puffs_framebuf *, void *, size_t);
|
||||
int puffs_framebuf_getdata_atoff(struct puffs_framebuf *, size_t,
|
||||
void *, size_t);
|
||||
|
||||
size_t puffs_framebuf_telloff(struct puffs_framebuf *);
|
||||
size_t puffs_framebuf_tellsize(struct puffs_framebuf *);
|
||||
size_t puffs_framebuf_remaining(struct puffs_framebuf *);
|
||||
int puffs_framebuf_seekset(struct puffs_framebuf *, size_t);
|
||||
int puffs_framebuf_getwindow(struct puffs_framebuf *, size_t,
|
||||
void **, size_t *);
|
||||
|
||||
int puffs_framev_enqueue_cc(struct puffs_cc *, int,
|
||||
struct puffs_framebuf *, int);
|
||||
int puffs_framev_enqueue_cb(struct puffs_usermount *, int,
|
||||
struct puffs_framebuf *,
|
||||
puffs_framev_cb, void *, int);
|
||||
int puffs_framev_enqueue_justsend(struct puffs_usermount *, int,
|
||||
struct puffs_framebuf *, int, int);
|
||||
int puffs_framev_enqueue_directreceive(struct puffs_cc *, int,
|
||||
struct puffs_framebuf *, int);
|
||||
int puffs_framev_enqueue_directsend(struct puffs_cc *, int,
|
||||
struct puffs_framebuf *, int);
|
||||
int puffs_framev_enqueue_waitevent(struct puffs_cc *, int, int *);
|
||||
int puffs_framev_framebuf_ccpromote(struct puffs_framebuf *,
|
||||
struct puffs_cc *);
|
||||
|
||||
int puffs_framev_addfd(struct puffs_usermount *, int, int);
|
||||
int puffs_framev_enablefd(struct puffs_usermount *, int, int);
|
||||
int puffs_framev_disablefd(struct puffs_usermount *, int, int);
|
||||
int puffs_framev_removefd(struct puffs_usermount *, int, int);
|
||||
void puffs_framev_removeonclose(struct puffs_usermount *, int, int);
|
||||
void puffs_framev_unmountonclose(struct puffs_usermount *, int, int);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _PUFFS_H_ */
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
.\" $NetBSD: puffs_cc.3,v 1.14 2009/04/11 16:48:53 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007, 2008 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd January 28, 2008
|
||||
.Dt PUFFS_CC 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_cc
|
||||
.Nd puffs continuation routines
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft void
|
||||
.Fn puffs_cc_yield "struct puffs_cc *pcc"
|
||||
.Ft void
|
||||
.Fn puffs_cc_continue "struct puffs_cc *pcc"
|
||||
.Ft void
|
||||
.Fn puffs_cc_schedule "struct puffs_cc *pcc"
|
||||
.Ft struct puffs_cc *
|
||||
.Fn puffs_cc_getcc "struct puffs_usermount *pu"
|
||||
.Sh DESCRIPTION
|
||||
These routines are used for the cooperative multitasking suite present
|
||||
in puffs.
|
||||
.Pp
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_cc_yield "pcc"
|
||||
Suspend and save the current execution context and return control
|
||||
to the previous point.
|
||||
In practice, from the file system author perspective, control returns
|
||||
back to where either the mainloop or where
|
||||
.Fn puffs_dispatch_exec
|
||||
was called from.
|
||||
.It Fn puffs_cc_continue pcc
|
||||
Will suspend current execution and return control to where it was
|
||||
before before calling
|
||||
.Fn puffs_cc_yield .
|
||||
This is rarely called directly but rather through
|
||||
.Fn puffs_dispatch_exec .
|
||||
.It Fn puffs_cc_schedule "pcc"
|
||||
Schedule a continuation.
|
||||
As opposed to
|
||||
.Fn puffs_cc_continue
|
||||
this call returns immediately.
|
||||
.Fa pcc
|
||||
will be scheduled sometime in the future.
|
||||
.It Fn puffs_cc_getcc "pu"
|
||||
Returns the current pcc or
|
||||
.Dv NULL
|
||||
if this is the main thread.
|
||||
.Em NOTE :
|
||||
The argument
|
||||
.Ar pu
|
||||
will most likely disappear at some point.
|
||||
.El
|
||||
.Pp
|
||||
Before calling
|
||||
.Fn puffs_cc_yield
|
||||
a file system will typically want to record some cookie value into its
|
||||
own internal bookkeeping.
|
||||
This cookie should be hooked to the
|
||||
.Va pcc
|
||||
so that the correct continuation can be continued when the event it
|
||||
was waiting for triggers.
|
||||
Alternatively, the
|
||||
.Xr puffs_framebuf 3
|
||||
framework and
|
||||
.Fn puffs_mainloop
|
||||
can be used for handling this automatically.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr puffs_framebuf 3
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
.\" $NetBSD: puffs_cred.3,v 1.5 2009/04/11 15:36:22 joerg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 18, 2007
|
||||
.Dt PUFFS_CRED 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_cred
|
||||
.Nd puffs credential and access control routines
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft int
|
||||
.Fn puffs_cred_getuid "const struct puffs_cred *pcr" "uid_t *uid"
|
||||
.Ft int
|
||||
.Fn puffs_cred_getgid "const struct puffs_cred *pcr" "gid_t *gid"
|
||||
.Ft int
|
||||
.Fo puffs_cred_getgroups
|
||||
.Fa "const struct puffs_cred *pcr" "gid_t *gids" "short *ngids"
|
||||
.Fc
|
||||
.Pp
|
||||
.Ft bool
|
||||
.Fn puffs_cred_isuid "const struct puffs_cred *pcr" "uid_t uid"
|
||||
.Ft bool
|
||||
.Fn puffs_cred_hasgroup "const struct puffs_cred *pcr" "gid_t gid"
|
||||
.Ft bool
|
||||
.Fn puffs_cred_iskernel "const struct puffs_cred *pcr"
|
||||
.Ft bool
|
||||
.Fn puffs_cred_isfs "const struct puffs_cred *pcr"
|
||||
.Ft bool
|
||||
.Fn puffs_cred_isjuggernaut "const struct puffs_cred *pcr"
|
||||
.Pp
|
||||
.Ft int
|
||||
.Fo puffs_access
|
||||
.Fa "enum vtype type" "mode_t file_mode" "uid_t owner" "gid_t group"
|
||||
.Fa "mode_t access_mode" "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_access_chown
|
||||
.Fa "uid_t owner" "gid_t group" "uid_t newowner" "gid_t newgroup"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_access_chmod
|
||||
.Fa "uid_t owner" "gid_t group" "enum vtype type" "mode_t newmode"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_access_times
|
||||
.Fa "uid_t owner" "gid_t group" "mode_t file_mode" "int va_utimes_null"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
These functions can be used to check operation credentials and perform
|
||||
access control.
|
||||
The structure
|
||||
.Vt struct puffs_cred
|
||||
can contain two types of credentials: ones belonging to users and
|
||||
ones belonging to the kernel.
|
||||
The latter is further divided into generic kernel credentials and
|
||||
file system credentials.
|
||||
The general rule is that these should be treated as more powerful
|
||||
than superuser credentials, but the file system is free to treat
|
||||
them as it sees fit.
|
||||
.Ss Credentials
|
||||
The
|
||||
.Fn puffs_cred_get
|
||||
family of functions fetch the uid or gid(s) from the given credential
|
||||
cookie.
|
||||
They return 0 for success or \-1 for an error and set
|
||||
.Va errno .
|
||||
An error happens when the credentials represent kernel or file system
|
||||
credentials and do not contain an uid or gid(s).
|
||||
.Pp
|
||||
For
|
||||
.Fn puffs_cred_getgroups ,
|
||||
the argument
|
||||
.Fa gids
|
||||
should point to an array with room for
|
||||
.Fa *ngids
|
||||
elements.
|
||||
.Pp
|
||||
The
|
||||
.Fn puffs_cred_is
|
||||
family of functions return 1 if the truth value of the function for
|
||||
.Fa pcr
|
||||
is true and 0 if it is false.
|
||||
The function
|
||||
.Fn puffs_cred_isjuggernaut
|
||||
is true if
|
||||
.Fa pcr
|
||||
describes superuser, kernel or file system credentials.
|
||||
.Ss Access Control
|
||||
To help the programmers task of emulating normal kernel file system
|
||||
access control semantics, several helper functions are provided to
|
||||
check if access is allowed.
|
||||
They return 0 if access should be permitted or an errno value to
|
||||
indicate that access should be denied with the returned value.
|
||||
.Pp
|
||||
.Fn puffs_access
|
||||
is equivalent to the kernel
|
||||
.Fn vaccess
|
||||
function.
|
||||
The arguments specify current information of the file to be
|
||||
tested with the exception of
|
||||
.Fa access_mode ,
|
||||
which is a combination of
|
||||
.Dv PUFFS_VREAD ,
|
||||
.Dv PUFFS_VWRITE
|
||||
and
|
||||
.Dv PUFFS_VEXEC
|
||||
indicating the desired file access mode.
|
||||
.Pp
|
||||
The rest of the functions provide UFS semantics for operations.
|
||||
.Fn puffs_access_chown
|
||||
checks if it is permissible to chown a file with the current uid
|
||||
and gid to the new uid and gid with the credentials of
|
||||
.Fa pcr .
|
||||
.Pp
|
||||
.Fn puffs_access_chmod
|
||||
checks against permission to chmod a file of type
|
||||
.Fa type
|
||||
to the mode
|
||||
.Fa newmode .
|
||||
.Pp
|
||||
Finally,
|
||||
.Fn puffs_access_times
|
||||
checks if it is allowable to update the timestamps of a file.
|
||||
The argument
|
||||
.Fa va_utimes_null
|
||||
signals if the flags
|
||||
.Dv VA_UTIMES_NULL
|
||||
was set in
|
||||
.Fa va_vaflags
|
||||
of
|
||||
.Va struct vattr .
|
||||
If coming from a path where this information is unavailable, passing
|
||||
0 as this argument restricts the permission of modification to the
|
||||
owner and superuser.
|
||||
Otherwise the function checks for write permissions to the node and
|
||||
returns success if the caller has write permissions.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr vnode 9
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
.\" $NetBSD: puffs_flush.3,v 1.8 2009/02/20 14:26:56 pooka Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 7, 2007
|
||||
.Dt PUFFS_FLUSH 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_flush
|
||||
.Nd puffs kernel cache flushing and invalidation routines
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft int
|
||||
.Fo puffs_inval_namecache_dir
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_inval_namecache_all "struct puffs_usermount *pu"
|
||||
.Ft int
|
||||
.Fo puffs_inval_pagecache_node
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_inval_pagecache_node_range
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie" "off_t start"
|
||||
.Fa "off_t end"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_flush_pagecache_node
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_flush_pagecache_node_range
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie" "off_t start"
|
||||
.Fa "off_t end"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
These routines are used inform the kernel that any information it might
|
||||
have cached is no longer valid.
|
||||
.Fn puffs_inval_namecache_dir
|
||||
invalidates the name cache for a given directory.
|
||||
The argument
|
||||
.Va cookie
|
||||
should describe an existing and valid directory cookie for the file
|
||||
system.
|
||||
Similarly,
|
||||
.Fn puffs_inval_namecache_all
|
||||
invalidates the name cache for the entire file system
|
||||
(this routine might go away).
|
||||
.Pp
|
||||
The cached pages (file contents) for a regular file described by
|
||||
.Va cookie
|
||||
are invalidated using
|
||||
.Fn puffs_inval_pagecache_node .
|
||||
A specific range can be invalidated using
|
||||
.Fn puffs_inval_pagecache_node_range
|
||||
for a platform specific page level granularity.
|
||||
The offset
|
||||
.Va start
|
||||
will be
|
||||
.Em truncated
|
||||
to a page boundary while
|
||||
.Va end
|
||||
will be
|
||||
.Em "rounded up"
|
||||
to the next page boundary.
|
||||
As a special case, specifying 0 as
|
||||
.Va end
|
||||
will invalidate all contents from
|
||||
.Va start
|
||||
to the end of the file.
|
||||
.Pp
|
||||
It is especially important to note that these routines will not only
|
||||
invalidate data in the "read cache", but also data in the "write back"
|
||||
cache (conceptually speaking; in reality they are the same cache), which
|
||||
has not yet been flushed to the file server.
|
||||
Therefore any unflushed data will be lost.
|
||||
.Pp
|
||||
The counterparts of the invalidation routines are the flushing routines
|
||||
.Fn puffs_flush_pagecache_node
|
||||
and
|
||||
.Fn puffs_flush_pagecache_node_range ,
|
||||
which force unwritten data from the kernel page cache to be written.
|
||||
For the flush range version, the same range rules as with the
|
||||
invalidation routine apply.
|
||||
The data is flushed asynchronously, i.e. if the routine returns
|
||||
successfully, all the caller knows is that the data has been queued
|
||||
for writing.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3
|
||||
|
|
@ -1,620 +0,0 @@
|
|||
.\" $NetBSD: puffs_framebuf.3,v 1.30 2015/02/16 10:48:50 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd September 6, 2008
|
||||
.Dt PUFFS_FRAMEBUF 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_framebuf
|
||||
.Nd buffering and event handling for networked file systems
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft struct puffs_framebuf *
|
||||
.Fn puffs_framebuf_make
|
||||
.Ft void
|
||||
.Fn puffs_framebuf_destroy "struct puffs_framebuf *pufbuf"
|
||||
.Ft void
|
||||
.Fn puffs_framebuf_recycle "struct puffs_framebuf *pufbuf"
|
||||
.Ft int
|
||||
.Fn puffs_framebuf_reserve_space "struct puffs_framebuf *pufbuf" "size_t space"
|
||||
.Ft int
|
||||
.Fo puffs_framebuf_putdata
|
||||
.Fa "struct puffs_framebuf *pufbuf" "const void *data" "size_t dlen"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framebuf_putdata_atoff
|
||||
.Fa "struct puffs_framebuf *pufbuf" "size_t offset" "const void *data"
|
||||
.Fa "size_t dlen"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framebuf_getdata
|
||||
.Fa "struct puffs_framebuf *pufbuf" "void *data" "size_t dlen"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framebuf_getdata_atoff
|
||||
.Fa "struct puffs_framebuf *pufbuf" "size_t offset"
|
||||
.Fa "void *data" "size_t dlen"
|
||||
.Fc
|
||||
.Ft size_t
|
||||
.Fn puffs_framebuf_telloff "struct puffs_framebuf *pufbuf"
|
||||
.Ft size_t
|
||||
.Fn puffs_framebuf_tellsize "struct puffs_framebuf *pufbuf"
|
||||
.Ft size_t
|
||||
.Fn puffs_framebuf_remaining "struct puffs_framebuf *pufbuf"
|
||||
.Ft int
|
||||
.Fn puffs_framebuf_seekset "struct puffs_framebuf *pufbuf" "size_t offset"
|
||||
.Ft int
|
||||
.Fo puffs_framebuf_getwindow
|
||||
.Fa "struct puffs_framebuf *pufbuf" "size_t offset"
|
||||
.Fa "void **winp" "size_t *winlen"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framev_enqueue_cc
|
||||
.Fa "struct puffs_cc *pcc" "int fd" "struct puffs_framebuf *pufbuf" "int flags"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_cb
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "void *arg" "int flags"
|
||||
.Fa "int error"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_enqueue_cb
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "puffs_framebuf_cb fcb" "void *fcb_arg" "int flags"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_enqueue_justsend
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "int waitreply" "int flags"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_enqueue_directsend
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_enqueue_directreceive
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framev_framebuf_ccpromote
|
||||
.Fa "struct puffs_framebuf *pufbuf" "struct puffs_cc *pcc"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_framev_enqueue_waitevent "struct puffs_cc *pcc" "int fd" "int *what"
|
||||
.Ft int
|
||||
.Fo puffs_framev_readframe_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "int fd" "int *done"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framev_writeframe_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
|
||||
.Fa "int fd" "int *done"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_framev_cmpframe_fn
|
||||
.Fa "struct puffs_usermount *pu"
|
||||
.Fa "struct puffs_framebuf *cmp1" "struct puffs_framebuf *cmp2" "int *notresp"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_gotframe_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_framebuf *pufbuf"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_fdnotify_fn
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "int what"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_framev_init
|
||||
.Fa "struct puffs_usermount *pu"
|
||||
.Fa "puffs_framev_readframe_fn rfb" "puffs_framev_writeframe_fn wfb"
|
||||
.Fa "puffs_framev_cmpframe_fn cmpfb" "puffs_framev_gotframe_fn gotfb"
|
||||
.Fa "puffs_framev_fdnotify_fn fdnotfn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn puffs_framev_addfd "struct puffs_usermount *pu" "int fd" "int what"
|
||||
.Ft int
|
||||
.Fn puffs_framev_enablefd "struct puffs_usermount *pu" "int fd" "int what"
|
||||
.Ft int
|
||||
.Fn puffs_framev_disablefd "struct puffs_usermount *pu" "int fd" "int what"
|
||||
.Ft int
|
||||
.Fn puffs_framev_removefd "struct puffs_usermount *pu" "int fd" "int error"
|
||||
.Ft void
|
||||
.Fo puffs_framev_unmountonclose
|
||||
.Fa "struct puffs_usermount *pu" "int fd" "int what"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
routines provide buffering and an event loop structured around the
|
||||
buffers.
|
||||
It operates on top of the puffs continuation framework,
|
||||
.Xr puffs_cc 3 ,
|
||||
and multiplexes execution automatically to an instance whenever
|
||||
one is runnable.
|
||||
.Pp
|
||||
The file system is entered in three different ways:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
An event arrives from the kernel and the
|
||||
.Xr puffs_ops 3
|
||||
callbacks are called to start processing the event.
|
||||
.It
|
||||
A file system which has sent out a request receives a response.
|
||||
Execution is resumed from the place where the file system yielded.
|
||||
.It
|
||||
A request from a peer arrives.
|
||||
A request is an incoming PDU which is not a response to any outstanding
|
||||
request.
|
||||
.El
|
||||
.Pp
|
||||
.Nm
|
||||
is used by defining various callbacks and providing I/O descriptors,
|
||||
which are then monitored for activity by the library.
|
||||
A descriptor, when present, can be either enabled or disabled for
|
||||
input and output.
|
||||
If a descriptor is not enabled for a certain direction, the callbacks
|
||||
will not be called even if there were activity on the descriptor.
|
||||
For example, even if a network socket has been added and there is
|
||||
input data in the socket buffer, the read callback will be called
|
||||
only if the socket has been enabled for reading.
|
||||
.Pp
|
||||
File descriptors are treated like sockets: they have two sides, a read
|
||||
side and a write side.
|
||||
The framework determines that one side of the descriptor has been
|
||||
closed if the supplied I/O callbacks return an error or if the I/O
|
||||
multiplexing call says a side has been closed.
|
||||
It is still possible, from the framework perspective, to write to a
|
||||
file descriptor whose read side is closed.
|
||||
However, it is not possible to wait for a response on such a file
|
||||
descriptor.
|
||||
Conversely, it is possible to read responses from a descriptor whose
|
||||
write side is closed.
|
||||
It should be stressed that the implementation underlying the file
|
||||
descriptor might not support this.
|
||||
.Pp
|
||||
The following callbacks can be defined, cf.
|
||||
.Fn puffs_framev_init ,
|
||||
and all are optional.
|
||||
None of them should block, because this would cause the entire file server
|
||||
to block.
|
||||
One option is to make the descriptors non-blocking before adding them.
|
||||
.Bl -tag -width "xfdnotfnx"
|
||||
.It rfb
|
||||
Read a frame from the file descriptor onto the specified buffer.
|
||||
.It wfb
|
||||
Write a frame from the specified buffer into the file descriptor.
|
||||
.It cmpfb
|
||||
Identify if a buffer is the response to the specified buffer.
|
||||
.It gotfb
|
||||
Called iff no outstanding request matches the incoming frame.
|
||||
In other words, this is called when we receive a request from a peer.
|
||||
.It fdnotfn
|
||||
Receive notifications about a change-of-state in a file descriptor's
|
||||
status.
|
||||
.El
|
||||
.Pp
|
||||
Better descriptions for each callback are given below.
|
||||
.Pp
|
||||
The buffers of
|
||||
.Nm
|
||||
provide automatic memory management of buffers for the file servers.
|
||||
They provide a cursor to the current buffer offset.
|
||||
Reading or writing data through the normal routines will advance that cursor.
|
||||
Additionally, the buffer size is provided to the user.
|
||||
It represents the maximum offset where data was written.
|
||||
.Pp
|
||||
Generally the write functions will fail if the cannot allocate enough
|
||||
memory to satisfy the buffer length requirements.
|
||||
Read functions will fail if the amount of data written to the buffer
|
||||
is not large enough to satisfy the read.
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_framebuf_make
|
||||
Create a buffer.
|
||||
Return the address of the buffer or
|
||||
.Dv NULL
|
||||
in case no memory was available.
|
||||
.It Fn puffs_framebuf_destroy pufbuf
|
||||
Free memory used by buffer.
|
||||
.It Fn puffs_framebuf_recycle pufbuf
|
||||
Reset offsets so that buffer can be reused.
|
||||
Does not free memory or reallocate memory.
|
||||
.It Fn puffs_framebuf_reserve_space pufbuf space
|
||||
Make sure that the buffer has
|
||||
.Ar space
|
||||
bytes of available memory starting from the current offset.
|
||||
This is not strictly necessary, but can be used for optimizations
|
||||
where it is known in advance how much memory will be required.
|
||||
.It Fn puffs_framebuf_putdata pufbuf data dlen
|
||||
Write
|
||||
.Ar dlen
|
||||
amount of data from the address
|
||||
.Ar data
|
||||
into the buffer.
|
||||
Moves the offset cursor forward
|
||||
.Ar dlen
|
||||
bytes.
|
||||
.It Fn puffs_framebuf_putdata_atoff pufbuf offset data dlen
|
||||
Like
|
||||
.Fn puffs_framebuf_putdata ,
|
||||
except writes data at buffer offset
|
||||
.Ar offset .
|
||||
It is legal to write past the current end of the buffer.
|
||||
Does NOT modify the current offset cursor.
|
||||
.It Fn puffs_framebuf_getdata pufbuf data dlen
|
||||
Read
|
||||
.Ar dlen
|
||||
bytes of data from the buffer into
|
||||
.Ar data .
|
||||
Advances the offset cursor.
|
||||
.It Fn puffs_framebuf_getdata_atoff pufbuf offset data dlen
|
||||
Read data from buffer position
|
||||
.Ar offset .
|
||||
Does NOT modify the offset cursor.
|
||||
.It Fn puffs_framebuf_telloff pufbuf
|
||||
Return the offset into the buffer.
|
||||
.It Fn puffs_framebuf_tellsize pufbuf
|
||||
Return the maximum offset where data has been written, i.e. buffer size.
|
||||
.It Fn puffs_framebuf_remaining pufbuf
|
||||
Distance from current offset to the end of the buffer, i.e. size-offset.
|
||||
.It Fn puffs_framebuf_seekset pufbuf offset
|
||||
Set the offset cursor to the position
|
||||
.Ar offset .
|
||||
This does NOT modify the buffer size, but reserves at least
|
||||
enough memory memory for a write to
|
||||
.Ar offset
|
||||
and will fail if memory cannot be allocated.
|
||||
.It Fn puffs_framebuf_getwindow pufbuf offset winp winlen
|
||||
Get a direct memory window into the buffer starting from
|
||||
.Ar offset .
|
||||
The maximum mapped window size will be
|
||||
.Ar winlen
|
||||
bytes, but this routine might return a smaller window and the caller
|
||||
should always check the actual mapped size after the call.
|
||||
The window is returned in
|
||||
.Ar winp .
|
||||
This function not modify the buffer offset, but it DOES set the buffer
|
||||
size to
|
||||
.Ar offset +
|
||||
.Ar winlen
|
||||
in case that value is greater than the current size.
|
||||
The window is valid until the next until the next
|
||||
.Fn puffs_framebuf
|
||||
call operating on the buffer in question.
|
||||
.It Fn puffs_framev_enqueue_cc pcc fd pufbuf flags
|
||||
Add the buffer
|
||||
.Ar pufbuf
|
||||
to outgoing queue of descriptor
|
||||
.Ar fd
|
||||
and yield with the continuation
|
||||
.Ar pcc .
|
||||
Execution is resumed once a response is received.
|
||||
Returns 0 if the buffer was successfully enqueued (not necessarily
|
||||
delivered) and non-zero to signal a non-recoverable error.
|
||||
.Pp
|
||||
Usually the buffer is placed at the end of the output queue.
|
||||
However, if
|
||||
.Ar flags
|
||||
contains
|
||||
.Dv PUFFS_FBQUEUE_URGENT ,
|
||||
.Ar pufbuf
|
||||
is placed in the front of the queue to be sent immediately after
|
||||
the current PDU (if any) has been sent.
|
||||
.It Fn puffs_framev_enqueue_cb pu fd pufbuf fcb fcb_arg flags
|
||||
Enqueue the buffer
|
||||
.Ar pufbuf
|
||||
for outgoing data and immediately return.
|
||||
Once a response arrives, the callback
|
||||
.Fn fcb
|
||||
will be called with the argument
|
||||
.Ar fcb_arg .
|
||||
The callback function
|
||||
.Fn fcb
|
||||
is responsible for freeing the buffer.
|
||||
Returns 0 if the buffer was successfully enqueued (not necessarily
|
||||
delivered) and non-zero to signal a non-recoverable error.
|
||||
.Pp
|
||||
See
|
||||
.Fn puffs_framev_enqueue_cc
|
||||
for
|
||||
.Ar flags .
|
||||
.It Fn puffs_framev_cb pu pufbuf arg error
|
||||
Callback function.
|
||||
Called when a response to a specific request arrives from the server.
|
||||
If
|
||||
.Ar error
|
||||
is non-zero, the framework was unable to obtain a response and the
|
||||
function should not examine the contents of
|
||||
.Ar pufbuf ,
|
||||
only do resource cleanup.
|
||||
May not block.
|
||||
.It Fn puffs_framev_enqueue_justsend pu fd pufbuf waitreply flags
|
||||
Enqueue the buffer
|
||||
.Ar pufbuf
|
||||
for outgoing traffic and immediately return.
|
||||
The parameter
|
||||
.Ar waitreply
|
||||
can be used to control if the buffer is to be freed immediately after
|
||||
sending of if a response is expected and the buffer should be freed
|
||||
only after the response arrives (receiving an unexpected message from
|
||||
the server is treated as an error).
|
||||
Returns 0 if the buffer was successfully enqueued (not necessarily
|
||||
delivered) and non-zero to signal a non-recoverable error.
|
||||
.Pp
|
||||
See
|
||||
.Fn puffs_framev_enqueue_cc
|
||||
for
|
||||
.Ar flags .
|
||||
.It Fn puffs_framev_enqueue_directsend pcc fd pufbuf flags
|
||||
Acts like
|
||||
.Fn puffs_framev_enqueue_justsend
|
||||
with the exception that the call yields until the frame has been sent.
|
||||
As opposed to
|
||||
.Fn puffs_framev_enqueue_cc ,
|
||||
the routine does not wait for input, but returns immediately after
|
||||
sending the frame.
|
||||
.Pp
|
||||
See
|
||||
.Fn puffs_framev_enqueue_cc
|
||||
for
|
||||
.Ar flags .
|
||||
.It Fn puffs_framev_enqueue_directreceive pcc fd pufbuf flags
|
||||
Receive data into
|
||||
.Ar pufbuf .
|
||||
This routine yields until a complete frame has been read into
|
||||
the buffer by the readframe routine.
|
||||
.Pp
|
||||
See
|
||||
.Fn puffs_framev_enqueue_cc
|
||||
for
|
||||
.Ar flags .
|
||||
.It Fn puffs_framev_framebuf_ccpromote pufbuf pcc
|
||||
Promote the framebuffer
|
||||
.Ar pufbuf
|
||||
sent with
|
||||
.Fn puffs_framev_enqueue_cb
|
||||
or
|
||||
.Fn puffs_framev_enqueue_justsend
|
||||
to a wait using
|
||||
.Ar pcc
|
||||
and yield until the result arrives.
|
||||
The response from the file server for
|
||||
.Ar pufbuf
|
||||
must not yet have arrived.
|
||||
If sent with
|
||||
.Fn puffs_framev_enqueue_justsend ,
|
||||
the call must be expecting a response.
|
||||
.It Fn puffs_framev_enqueue_waitevent pcc fd what
|
||||
Waits for an event in
|
||||
.Ar what
|
||||
to happen on file descriptor
|
||||
.Ar fd .
|
||||
The events which happened are returned back in
|
||||
.Ar what .
|
||||
The possible events are
|
||||
.Dv PUFFS_FBIO_READ ,
|
||||
.Dv PUFFS_FBIO_WRITE ,
|
||||
and
|
||||
.Dv PUFFS_FBIO_ERROR ,
|
||||
specifying read, write and error conditions, respectively.
|
||||
Error is always checked.
|
||||
.Pp
|
||||
This call does not depend on if the events were previously enabled on
|
||||
the file descriptor - the specified events are always checked
|
||||
regardless.
|
||||
.Pp
|
||||
There is currently no other way to cancel or timeout a call except by
|
||||
removing the file descriptor in question.
|
||||
This may change in the future.
|
||||
.It Fn puffs_framev_readframe_fn pu pufbuf fd done
|
||||
Callback function.
|
||||
Read at most one frame from file descriptor
|
||||
.Ar fd
|
||||
into the buffer
|
||||
.Ar pufbuf .
|
||||
If a complete frame is read, the value pointed to by
|
||||
.Ar done
|
||||
must be set to 1.
|
||||
This function should return 0 on success (even if a complete frame was not
|
||||
yet read) and a non-zero
|
||||
.Er errno
|
||||
to signal a fatal error.
|
||||
In case a fatal error is returned, the read side of the file descriptor
|
||||
is marked closed.
|
||||
This routine will be called with the same buffer argument until a
|
||||
complete frame has been read.
|
||||
May not block.
|
||||
.It Fn puffs_framev_writeframe_fn pu pufbuf fd done
|
||||
Write the frame contained in
|
||||
.Ar pufbuf
|
||||
to the file descriptor
|
||||
.Ar fd .
|
||||
In case the entire frame is successfully written,
|
||||
.Ar *done
|
||||
should be set to 1.
|
||||
This function should return 0 on success (even if a complete frame was not
|
||||
yet written) and a non-zero
|
||||
.Er errno
|
||||
to signal a fatal error.
|
||||
In case a fatal error is returned, the write side of the file descriptor
|
||||
is marked closed.
|
||||
This routine will be called with the same buffer argument until the
|
||||
complete frame has been written.
|
||||
May not block.
|
||||
.Pp
|
||||
It is a good idea to make sure that this function can handle a possible
|
||||
.Dv SIGPIPE
|
||||
caused by a closed connection.
|
||||
For example, the file server can opt to trap
|
||||
.Dv SIGPIPE
|
||||
or, if writing to a socket, call
|
||||
.Fn send
|
||||
with the flag
|
||||
.Dv MSG_NOSIGNAL
|
||||
instead of using
|
||||
.Fn write .
|
||||
.It Fn puffs_framev_cmpframe_fn pu pufbuf_cmp1 pufbuf_cmp2 notresp
|
||||
Compare the file system internal request tags in
|
||||
.Ar pufbuf_cmp1
|
||||
and
|
||||
.Ar pufbuf_cmp2 .
|
||||
Should return 0 if the tags are equal, 1 if first buffer's tag is
|
||||
greater than the second and \-1 if it is smaller.
|
||||
The definitions "greater" and "smaller" are used transparently by
|
||||
the library, e.g. like
|
||||
.Xr qsort 3 .
|
||||
If it can be determined from
|
||||
.Ar pufbuf_cmp1
|
||||
that it is not a response to any outstanding request,
|
||||
.Ar notresp
|
||||
should be set to non-zero.
|
||||
This will cause
|
||||
.Nm
|
||||
to skip the test of the buffer against the rest of the outstanding
|
||||
request.
|
||||
May not block.
|
||||
.It Fn puffs_framev_gotframe_fn pu pufbuf
|
||||
Called when no outstanding request matches an incoming frame.
|
||||
The ownership of
|
||||
.Ar pufbuf
|
||||
is transferred to the called function and must be destroyed once
|
||||
processing is over.
|
||||
May not block.
|
||||
.It Fn puffs_framev_fdnotify_fn pu fd what
|
||||
Is called when the read or write side of the file descriptor
|
||||
.Ar fd
|
||||
is closed.
|
||||
It is called once for each side, the bitmask parameter
|
||||
.Ar what
|
||||
specified what is currently closed:
|
||||
.Dv PUFFS_FBIO_READ
|
||||
and
|
||||
.Dv PUFFS_FBIO_WRITE
|
||||
for read and write, respectively.
|
||||
.It Fn puffs_framev_init pu rfb wfb cmpfb gotfb fdnotfn
|
||||
Initializes the given callbacks to the system.
|
||||
They will be used when
|
||||
.Fn puffs_mainloop
|
||||
is called.
|
||||
The framework provides the routines
|
||||
.Fn puffs_framev_removeonclose
|
||||
and
|
||||
.Fn puffs_framev_unmountonclose ,
|
||||
which can be given as
|
||||
.Ar fdnotfn .
|
||||
The first one removes the file descriptor once both sides are closed
|
||||
while the second one unmounts the file system and exits the mainloop.
|
||||
.It Fn puffs_framev_addfd pu fd what
|
||||
Add file descriptor
|
||||
.Ar fd
|
||||
to be handled by the framework.
|
||||
It is legal to add a file descriptor either before calling
|
||||
.Fn puffs_mainloop
|
||||
or at time when running.
|
||||
The parameter
|
||||
.Ar what
|
||||
controls enabling of input and output events and can be a bitwise
|
||||
combination of
|
||||
.Dv PUFFS_FBIO_READ
|
||||
and
|
||||
.Dv PUFFS_FBIO_WRITE .
|
||||
If not specified, the descriptor will be in a disabled state.
|
||||
.It Fn puffs_framev_enablefd pu fd what
|
||||
Enable events of type
|
||||
.Ar what
|
||||
for file descriptor
|
||||
.Ar fd .
|
||||
.It Fn puffs_framev_disablefd pu fd what
|
||||
Disable events of type
|
||||
.Ar what
|
||||
for file descriptor
|
||||
.Ar fd .
|
||||
.It Fn puffs_framev_removefd pu fd error
|
||||
Remove file descriptor
|
||||
.Ar fd
|
||||
from the list of descriptors handled by the framework.
|
||||
Removing a file descriptor causes all operations blocked either on
|
||||
output or input to be released with the error value
|
||||
.Ar error .
|
||||
In case 0 is supplied as this parameter,
|
||||
.Er ECONNRESET
|
||||
is used.
|
||||
.Pp
|
||||
The file system
|
||||
.Em must
|
||||
explicitly remove each fd it has added.
|
||||
A good place to do this is
|
||||
.Fn puffs_framev_fdnotify_fn
|
||||
or
|
||||
.Fn puffs_node_reclaim ,
|
||||
depending a little on the structure of the file system.
|
||||
.It Fn puffs_framev_unmountonclose pu fd what
|
||||
This is library provided convenience routine for
|
||||
.Fn puffs_framev_fdnotify_fn .
|
||||
It unmounts the file system when both the read and write side are
|
||||
closed.
|
||||
It is useful for file systems such as
|
||||
.Xr mount_psshfs 8
|
||||
which depend on a single connection.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
These functions generally return \-1 to signal error and set
|
||||
.Er errno
|
||||
to indicate the type of error.
|
||||
.Sh CODE REFERENCES
|
||||
The current users of
|
||||
.Nm
|
||||
in the tree are
|
||||
.Xr mount_psshfs 8
|
||||
and
|
||||
.Xr mount_9p 8 .
|
||||
See
|
||||
.Pa src/usr.sbin/puffs/mount_psshfs
|
||||
and
|
||||
.Pa src/usr.sbin/puffs/mount_9p
|
||||
for the respective usage examples.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr puffs_cc 3 ,
|
||||
.Xr puffs_ops 3
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%D September 2007
|
||||
.%I Helsinki University of Technology
|
||||
.%R Tech Report TKK-TKO-B157
|
||||
.%T Using puffs for Implementing Client-Server Distributed File Systems
|
||||
.Re
|
||||
.Rs
|
||||
.%A Antti Kantee
|
||||
.%D March 2008
|
||||
.%J Proceedings of AsiaBSDCon 2008
|
||||
.%P pp. 55-70
|
||||
.%T Send and Receive of File System Protocols: Userspace Approach With puffs
|
||||
.Re
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
.\" $NetBSD: puffs_node.3,v 1.5 2009/05/13 22:42:31 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd June 24, 2007
|
||||
.Dt PUFFS_NODE 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_node
|
||||
.Nd puffs node routines
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft struct puffs_node *
|
||||
.Fn puffs_pn_new "struct puffs_usermount *pu" "void *priv"
|
||||
.Ft void *
|
||||
.Fo puffs_nodewalk_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_node *pn" "void *arg"
|
||||
.Fc
|
||||
.Ft void *
|
||||
.Fo puffs_pn_nodewalk
|
||||
.Fa "struct puffs_usermount *pu" "puffs_nodewalk_fn nwfn" "void *arg"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fn puffs_pn_remove "struct puffs_node *pn"
|
||||
.Ft void
|
||||
.Fn puffs_pn_put "struct puffs_node *pn"
|
||||
.Sh DESCRIPTION
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_pn_new pu priv
|
||||
Create a new node and attach it to the mountpoint
|
||||
.Ar pu .
|
||||
The argument
|
||||
.Ar priv
|
||||
can be used for associating file system specific data with the new
|
||||
node and will not be accessed by puffs.
|
||||
.It Fn puffs_nodewalk_fn pu pn arg
|
||||
A callback for
|
||||
.Fn puffs_nodewalk .
|
||||
The list of nodes is iterated in the argument
|
||||
.Ar pn
|
||||
and the argument
|
||||
.Ar arg
|
||||
is the argument given to
|
||||
.Fn puffs_nodewalk .
|
||||
.It Fn puffs_nodewalk pu nwfn arg
|
||||
Walk all nodes associted with the mountpoint
|
||||
.Ar pu
|
||||
and call
|
||||
.Fn nwfn
|
||||
for them.
|
||||
The walk is aborted if
|
||||
.Fn puffs_nodewalk_fn
|
||||
returns a value which is not
|
||||
.Dv NULL .
|
||||
This value is also returned this function.
|
||||
In case the whole set of nodes is traversed,
|
||||
.Dv NULL
|
||||
is returned.
|
||||
This function is useful for example in handling the
|
||||
.Fn puffs_fs_sync
|
||||
callback, when cached data for every node should be flushed to stable
|
||||
storage.
|
||||
.It Fn puffs_pn_remove pn
|
||||
Signal that a node has been removed from the file system, but do not
|
||||
yet release resources associated with the node.
|
||||
This will prevent the nodewalk functions from accessing the node.
|
||||
If necessary, this is usually called from
|
||||
.Fn puffs_node_remove
|
||||
and
|
||||
.Fn puffs_node_rmdir .
|
||||
.It Fn puffs_pn_put pn
|
||||
Free all resources associated with node
|
||||
.Ar pn .
|
||||
This is typically called from
|
||||
.Fn puffs_node_reclaim .
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3
|
||||
|
|
@ -1,955 +0,0 @@
|
|||
.\" $NetBSD: puffs_ops.3,v 1.42 2015/02/16 10:48:56 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 31, 2014
|
||||
.Dt PUFFS_OPS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_ops
|
||||
.Nd puffs callback operations
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft int
|
||||
.Fo puffs_fs_statvfs
|
||||
.Fa "struct puffs_usermount *pu" "struct statvfs *sbp"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_fs_sync
|
||||
.Fa "struct puffs_usermount *pu" "int waitfor" "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_fs_fhtonode
|
||||
.Fa "struct puffs_usermount *pu" "void *fid" "size_t fidsize"
|
||||
.Fa "struct puffs_newinfo *pni"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_fs_nodetofh
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t cookie" "void *fid"
|
||||
.Fa "size_t *fidsize"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fo puffs_fs_extattrctl
|
||||
.Fa "struct puffs_usermount *pu" "int cmd" "puffs_cookie_t cookie" "int flags"
|
||||
.Fa "int attrnamespace" "const char *attrname"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_fs_unmount
|
||||
.Fa "struct puffs_usermount *pu" "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_lookup
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "struct puffs_newinfo *pni" "const struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_create
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "struct puffs_newinfo *pni" "const struct puffs_cn *pcn"
|
||||
.Fa "const struct vattr *vap"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_mknod
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "struct puffs_newinfo *pni" "const struct puffs_cn *pcn"
|
||||
.Fa "const struct vattr *vap"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_open
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int mode"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_open2
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int modep"
|
||||
.Fa "const struct puffs_cred *pcr" "int *oflags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_close
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int flags"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_access
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int mode"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_getattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "struct vattr *vap"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_setattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "const struct vattr *vap"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_getattr_ttl
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "struct vattr *vap"
|
||||
.Fa "const struct puffs_cred *pcr" "struct timespec *va_ttl"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_setattr_ttl
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "const struct vattr *vap"
|
||||
.Fa "const struct puffs_cred *pcr" "struct timespec *va_ttl" "int xflag"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_poll
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int *events"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_mmap
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int flags"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_fsync
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "const struct puffs_cred *pcr" "int flags" "off_t offlo" "off_t offhi"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_seek
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "off_t oldoff"
|
||||
.Fa "off_t newoff" "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_remove
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "puffs_cookie_t targ"
|
||||
.Fa "const struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_link
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "puffs_cookie_t targ"
|
||||
.Fa "const struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_rename
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "puffs_cookie_t src"
|
||||
.Fa "const struct puffs_cn *pcn_src" "puffs_cookie_t targ_dir"
|
||||
.Fa "puffs_cookie_t targ" "const struct puffs_cn *pcn_targ"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_mkdir
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "struct puffs_newinfo *pni" "const struct puffs_cn *pcn"
|
||||
.Fa "const struct vattr *vap"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_rmdir
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "puffs_cookie_t targ"
|
||||
.Fa "const struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_readdir
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "struct dirent *dent"
|
||||
.Fa "off_t *readoff" "size_t *reslen" "const struct puffs_cred *pcr"
|
||||
.Fa "int *eofflag" "off_t *cookies" "size_t *ncookies"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_symlink
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "struct puffs_newinfo *pni"
|
||||
.Fa "const struct puffs_cn *pcn_src" "const struct vattr *vap"
|
||||
.Fa "const char *link_target"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_readlink
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "const struct puffs_cred *pcr" "char *link" "size_t *linklen"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_read
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "uint8_t *buf"
|
||||
.Fa "off_t offset" "size_t *resid" "const struct puffs_cred *pcr" "int ioflag"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_write
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "uint8_t *buf"
|
||||
.Fa "off_t offset" "size_t *resid" "const struct puffs_cred *pcr" "int ioflag"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_write2
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "uint8_t *buf"
|
||||
.Fa "off_t offset" "size_t *resid" "const struct puffs_cred *pcr" "int ioflag"
|
||||
.Fa "int xflag"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_abortop
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fa "const struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_getextattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int attrnamespace"
|
||||
.Fa "const char *attrname" "size_t *attrsize" "uint8_t *attr" "size_t *resid"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_setextattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int attrnamespace"
|
||||
.Fa "const char *attrname" "uint8_t *attr" "size_t *resid"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_listextattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int attrnamespace"
|
||||
.Fa "size_t *attrssize" "uint8_t *attrs" "iint flag" "size_t *resid"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_deleteextattr
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int attrnamespace"
|
||||
.Fa "const char *attrname"
|
||||
.Fa "const struct puffs_cred *pcr"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_fallocate
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "off_t pos" "off_t len"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_fdiscard
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "off_t pos" "off_t len"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_print
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_reclaim
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_reclaim2
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc" "int nlookup"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo puffs_node_inactive
|
||||
.Fa "struct puffs_usermount *pu" "puffs_cookie_t opc"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fn puffs_setback "struct puffs_cc *pcc" "int op"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setcookie "struct puffs_newinfo *pni" "puffs_cookie_t cookie"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setvtype "struct puffs_newinfo *pni" "enum vtype vtype"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setsize "struct puffs_newinfo *pni" "voff_t size"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setrdev "struct puffs_newinfo *pni" "dev_t rdev"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setva "struct puffs_newinfo *pni" "struct vattr *vap"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setvattl "struct puffs_newinfo *pni" "struct timespec *va_ttl"
|
||||
.Ft void
|
||||
.Fn puffs_newinfo_setcnttl "struct puffs_newinfo *pni" "struct timespec *cn_ttl"
|
||||
.Sh DESCRIPTION
|
||||
The operations
|
||||
.Nm puffs
|
||||
requires to function can be divided into two categories: file system
|
||||
callbacks and node callbacks.
|
||||
The former affect the entire file system while the latter are targeted
|
||||
at a file or a directory and a file.
|
||||
They are roughly equivalent to the vfs and vnode operations in the
|
||||
kernel.
|
||||
.Pp
|
||||
All callbacks can be prototyped with the file system name and operation
|
||||
name using the macro
|
||||
.Fn PUFFSOP_PROTOS fsname .
|
||||
.Ss File system callbacks (puffs_fs)
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_fs_statvfs "pu" "sbp"
|
||||
The following fields of the argument
|
||||
.Fa sbp
|
||||
need to be filled:
|
||||
.Bd -literal
|
||||
* unsigned long f_bsize; file system block size
|
||||
* unsigned long f_frsize; fundamental file system block size
|
||||
* fsblkcnt_t f_blocks; number of blocks in file system,
|
||||
* (in units of f_frsize)
|
||||
*
|
||||
* fsblkcnt_t f_bfree; free blocks avail in file system
|
||||
* fsblkcnt_t f_bavail; free blocks avail to non-root
|
||||
* fsblkcnt_t f_bresvd; blocks reserved for root
|
||||
|
||||
* fsfilcnt_t f_files; total file nodes in file system
|
||||
* fsfilcnt_t f_ffree; free file nodes in file system
|
||||
* fsfilcnt_t f_favail; free file nodes avail to non-root
|
||||
* fsfilcnt_t f_fresvd; file nodes reserved for root
|
||||
|
||||
.Ed
|
||||
.It Fn puffs_fs_sync "pu" "waitfor" "pcr"
|
||||
All the dirty buffers that have been cached at the file server
|
||||
level including metadata should be committed to stable storage.
|
||||
The
|
||||
.Fa waitfor
|
||||
parameter affects the operation.
|
||||
Possible values are:
|
||||
.Bl -tag -width XMNT_NOWAITX
|
||||
.It Dv MNT_WAIT
|
||||
Wait for all I/O for complete until returning.
|
||||
.It Dv MNT_NOWAIT
|
||||
Initiate I/O, but do not wait for completion.
|
||||
.It Dv MNT_LAZY
|
||||
Synchorize data not synchoronized by the file system syncer,
|
||||
i.e., data not written when
|
||||
.Fn node_fsync
|
||||
is called with
|
||||
.Dv FSYNC_LAZY .
|
||||
.El
|
||||
.Pp
|
||||
The credentials for the initiator of the sync operation are present in
|
||||
.Fa pcr
|
||||
and will usually be either file system or kernel credentials, but might
|
||||
also be user credentials.
|
||||
However, most of the time it is advisable to sync regardless of the
|
||||
credentials of the caller.
|
||||
.It Fn puffs_fs_fhtonode "pu" "fid" "fidsize" "pni"
|
||||
Translates a file handle
|
||||
.Fa fid
|
||||
to a node.
|
||||
The parameter
|
||||
.Fa fidsize
|
||||
indicates how large the file handle is.
|
||||
In case the file system's handles are static length, this parameter can
|
||||
be ignored as the kernel guarantees all file handles passed to the file
|
||||
server are of correct length.
|
||||
For dynamic length handles the field should be examined and
|
||||
.Er EINVAL
|
||||
returned in case the file handle length is not correct.
|
||||
.Pp
|
||||
This function provides essentially the same information to the kernel as
|
||||
.Fn puffs_node_lookup .
|
||||
The information is necessary for creating a new vnode corresponding to
|
||||
the file handle.
|
||||
.It Fn puffs_fs_nodetofh "pu" "cookie" "fid" "fidsize"
|
||||
Create a file handle from the node described by
|
||||
.Fa cookie .
|
||||
The file handle should contain enough information to reliably identify
|
||||
the node even after reboots and the pathname/inode being replaced by
|
||||
another file.
|
||||
If this is not possible, it is up to the author of the file system to
|
||||
act responsibly and decide if the file system can support file handles
|
||||
at all.
|
||||
.Pp
|
||||
For file systems which want dynamic length file handles, this function
|
||||
must check if the file handle space indicated by
|
||||
.Fa fidsize
|
||||
is large enough to accommodate the file handle for the node.
|
||||
If not, it must fill in the correct size and return
|
||||
.Er E2BIG .
|
||||
In either case, the handle length should be supplied to the kernel in
|
||||
.Fa fidsize .
|
||||
File systems with static length handles can ignore the size parameter as
|
||||
the kernel always supplies the correct size buffer.
|
||||
.It Fn puffs_fs_unmount "pu" "flags"
|
||||
Unmount the file system.
|
||||
The kernel has assumedly flushed all cached data when this callback
|
||||
is executed.
|
||||
If the file system cannot currently be safely be unmounted, for whatever
|
||||
reason, the kernel will honor an error value and not forcibly unmount.
|
||||
However, if the flag
|
||||
.Dv MNT_FORCE
|
||||
is not honored by the file server, the kernel will forcibly unmount
|
||||
the file system.
|
||||
.El
|
||||
.Ss Node callbacks
|
||||
These operations operate in the level of individual files.
|
||||
The file cookie is always provided as the second argument
|
||||
.Fa opc .
|
||||
If the operation is for a file, it will be the cookie of the file.
|
||||
The case the operation involves a directory (such as
|
||||
.Dq create file in directory ) ,
|
||||
the cookie will be for the directory.
|
||||
Some operations take additional cookies to describe the rest of
|
||||
the operands.
|
||||
The return value 0 signals success, else an appropriate errno value
|
||||
should be returned.
|
||||
Please note that neither this list nor the descriptions are complete.
|
||||
.Bl -tag -width xxxx
|
||||
.It Fn puffs_node_lookup "pu" "opc" "pni" "pcn"
|
||||
This function is used to locate nodes, or in other words translate
|
||||
pathname components to file system data structures.
|
||||
The implementation should match the name in
|
||||
.Fa pcn
|
||||
against the existing entries in the directory provided by the cookie
|
||||
.Fa opc .
|
||||
If found, the cookie for the located node should be set in
|
||||
.Fa pni
|
||||
using
|
||||
.Fn puffs_newinfo_setcookie .
|
||||
Additionally, the vnode type and size (latter applicable to regular files only)
|
||||
should be set using
|
||||
.Fn puffs_newinfo_setvtype
|
||||
and
|
||||
.Fn puffs_newinfo_setsize ,
|
||||
respectively.
|
||||
If the located entry is a block device or character device file,
|
||||
the dev_t for the entry should be set using
|
||||
.Fn puffs_newinfo_setrdev .
|
||||
.Pp
|
||||
If
|
||||
.Fn puffs_init
|
||||
was called with
|
||||
.Dv PUFFS_KFLAG_CACHE_FS_TTL
|
||||
then
|
||||
.Fn puffs_newinfo_setva ,
|
||||
.Fn puffs_newinfo_setvattl ,
|
||||
and
|
||||
.Fn puffs_newinfo_setcnttl
|
||||
can be called to specify the new node attributes, cached attributes
|
||||
time to live, and cached name time to live.
|
||||
.Pp
|
||||
The type of operation is found from
|
||||
.Va pcn-\*[Gt]pcn_nameiop :
|
||||
.Bl -tag -width XNAMEI_LOOKUPX
|
||||
.It Dv NAMEI_LOOKUP
|
||||
Normal lookup operation.
|
||||
.It Dv NAMEI_CREATE
|
||||
Lookup to create a node.
|
||||
.It Dv NAMEI_DELETE
|
||||
Lookup for node deletion.
|
||||
.It Dv NAMEI_RENAME
|
||||
Lookup for the target of a rename operation (source will be looked
|
||||
up using
|
||||
.Dv NAMEI_DELETE ) .
|
||||
.El
|
||||
.Pp
|
||||
The final component from a pathname lookup usually requires special
|
||||
treatment.
|
||||
It can be identified by looking at the
|
||||
.Va pcn-\*[Gt]pcn_flags
|
||||
fields for the flag
|
||||
.Dv PUFFSLOOKUP_ISLASTCN .
|
||||
For example, in most cases the lookup operation will want to check if
|
||||
a delete, rename or create operation has enough credentials to perform
|
||||
the operation.
|
||||
.Pp
|
||||
The return value 0 signals a found node and a nonzero value signals
|
||||
an errno.
|
||||
As a special case,
|
||||
.Er ENOENT
|
||||
signals "success" for cases where the lookup operation is
|
||||
.Dv NAMEI_CREATE
|
||||
or
|
||||
.Dv NAMEI_RENAME .
|
||||
Failure in these cases can be signalled by returning another appropriate
|
||||
error code, for example
|
||||
.Er EACCESS .
|
||||
.Pp
|
||||
Usually a null-terminated string for the next pathname component is
|
||||
provided in
|
||||
.Ar pcn-\*[Gt]pcn_name .
|
||||
In case the file system is using the option
|
||||
.Dv PUFFS_KFLAG_LOOKUP_FULLPNBUF ,
|
||||
the remainder of the complete pathname under lookup is found in
|
||||
the same location.
|
||||
.Ar pcn-\*[Gt]pcn_namelen
|
||||
always specifies the length of the next component.
|
||||
If operating with a full path, the file system is allowed to consume
|
||||
more than the next component's length in node lookup.
|
||||
This is done by setting
|
||||
.Ar pcn-\*[Gt]pcn_consume
|
||||
to indicate the amount of
|
||||
.Em extra
|
||||
characters in addition to
|
||||
.Ar pcn-\*[Gt]pcn_namelen
|
||||
processed.
|
||||
.It Fn puffs_node_create "pu" "opc" "pni" "pcn" "va"
|
||||
.It Fn puffs_node_mkdir "pu" "opc" "pni" "pcn" "va"
|
||||
.It Fn puffs_node_mknod "pu" "opc" "pni" "pcn" "va"
|
||||
A file node is created in the directory denoted by the cookie
|
||||
.Fa opc
|
||||
by any of the above callbacks.
|
||||
The name of the new file can be found from
|
||||
.Fa pcn
|
||||
and the attributes are specified by
|
||||
.Fa va
|
||||
and the cookie for the newly created node should be set in
|
||||
.Fa pni .
|
||||
The only difference between these three is that they create a regular
|
||||
file, directory and device special file, respectively.
|
||||
.Pp
|
||||
In case of mknod, the device identifier can be found in
|
||||
.Fa va-\*[Gt]va_rdev .
|
||||
.It Fn puffs_node_open "pu" "opc" "mode" "pcr"
|
||||
.It Fn puffs_node_open2 "pu" "opc" "mode" "pcr" "oflags"
|
||||
Open the node denoted by the cookie
|
||||
.Fa opc .
|
||||
The parameter
|
||||
.Fa mode
|
||||
specifies the flags that
|
||||
.Xr open 2
|
||||
was called with, e.g.
|
||||
.Dv O_APPEND
|
||||
and
|
||||
.Dv O_NONBLOCK .
|
||||
.Fn puffs_node_open2
|
||||
allows the file system to pass back information for the file in
|
||||
.Fa oflags .
|
||||
The only implemented flag for now is
|
||||
.Dv PUFFS_OPEN_IO_DIRECT
|
||||
that cause file read/write to bypass the page cache.
|
||||
.It Fn puffs_node_close "pu" "opc" "flags" "pcr"
|
||||
Close a node.
|
||||
The parameter
|
||||
.Fa flags
|
||||
parameter describes the flags that the file was opened with.
|
||||
.It Fn puffs_node_access "pu" "opc" "mode" "pcr"
|
||||
Check if the credentials of
|
||||
.Fa pcr
|
||||
have the right to perform the operation specified by
|
||||
.Fa mode
|
||||
onto the node
|
||||
.Fa opc .
|
||||
The argument
|
||||
.Fa mode
|
||||
can specify read, write or execute by
|
||||
.Dv PUFFS_VREAD ,
|
||||
.Dv PUFFS_VWRITE ,
|
||||
and
|
||||
.Dv PUFFS_VEXEC ,
|
||||
respectively.
|
||||
.It Fn puffs_node_getattr "pu" "opc" "va" "pcr"
|
||||
The attributes of the node specified by
|
||||
.Fa opc
|
||||
must be copied to the space pointed by
|
||||
.Fa va .
|
||||
.It Fn puffs_node_getattr_ttl "pu" "opc" "va" "pcr" "va_ttl"
|
||||
Same as
|
||||
.Fn puffs_node_getattr
|
||||
with cached attribute time to live specified in
|
||||
.Fa va_ttl
|
||||
.It Fn puffs_node_setattr "pu" "opc" "va" "pcr"
|
||||
The attributes for the node specified by
|
||||
.Fa opc
|
||||
must be set to those contained in
|
||||
.Fa va .
|
||||
Only fields of
|
||||
.Fa va
|
||||
which contain a value different from
|
||||
.Dv PUFFS_VNOVAL
|
||||
(typecast to the field's type!) contain a valid value.
|
||||
.It Fn puffs_node_setattr_ttl "pu" "opc" "va" "pcr" "va_ttl" "xflag"
|
||||
Same as
|
||||
.Fn puffs_node_setattr
|
||||
with cached attribute time to live specified in
|
||||
.Fa va_ttl .
|
||||
.Dv PUFFS_SETATTR_FAF
|
||||
will be set in
|
||||
.Fa xflag
|
||||
for Fire-And-Forget operations.
|
||||
.It Fn puffs_node_poll "pu" "opc" "events"
|
||||
Poll for events on node
|
||||
.Ar opc .
|
||||
If
|
||||
.Xr poll 2
|
||||
events specified in
|
||||
.Ar events
|
||||
are available, the function should set the bitmask to match available
|
||||
events and return immediately.
|
||||
Otherwise, the function should block (yield) until some events in
|
||||
.Ar events
|
||||
become available and only then set the
|
||||
.Ar events
|
||||
bitmask and return.
|
||||
.Pp
|
||||
In case this function returns an error,
|
||||
.Dv POLLERR
|
||||
(or its
|
||||
.Xr select 2
|
||||
equivalent) will be delivered to the calling process.
|
||||
.Pp
|
||||
.Em NOTE!
|
||||
The system call interface for
|
||||
.Fn poll
|
||||
contains a timeout parameter.
|
||||
At this level, however, the timeout is not supplied.
|
||||
In case input does not arrive, the file system should periodically
|
||||
unblock and return 0 new events to avoid hanging forever.
|
||||
This will hopefully be better supported by libpuffs in the future.
|
||||
.It Fn puffs_node_mmap "pu" "opc" "flags" "pcr"
|
||||
Called when a regular file is being memory mapped by
|
||||
.Xr mmap 2 .
|
||||
.Fa flags
|
||||
is currently always 0.
|
||||
.It Fn puffs_node_fsync "pu" "opc" "pcr" "flags" "offlo" "offhi"
|
||||
Sychronize a node's contents onto stable storage.
|
||||
This is necessary only if the file server caches some information
|
||||
before committing it.
|
||||
The parameter
|
||||
.Fa flags
|
||||
specifies the minimum level of sychronization required (XXX: they are
|
||||
not yet available).
|
||||
The parameters
|
||||
.Fa offlo
|
||||
and
|
||||
.Fa offhi
|
||||
specify the data offsets requiring to be synced.
|
||||
A high offset of 0 means sync from
|
||||
.Fa offlo
|
||||
to the end of the file.
|
||||
.It Fn puffs_node_seek "pu" "opc" "oldoff" "newoff" "pcr"
|
||||
Test if the node
|
||||
.Ar opc
|
||||
is seekable to the location
|
||||
.Ar newoff .
|
||||
The argument
|
||||
.Ar oldoff
|
||||
specifies the offset we are starting the seek from.
|
||||
Most file systems dealing only with regular will choose to not
|
||||
implement this.
|
||||
However, it is useful for example in cases where files are
|
||||
unseekable streams.
|
||||
.It Fn puffs_node_remove "pu" "opc" "targ" "pcn"
|
||||
.It Fn puffs_node_rmdir "pu" "opc" "targ" "pcn"
|
||||
Remove the node
|
||||
.Fa targ
|
||||
from the directory indicated by
|
||||
.Fa opc .
|
||||
The directory entry name to be removed is provided by
|
||||
.Fa pcn .
|
||||
The rmdir operation removes only directories, while the remove
|
||||
operation removes all other types except directories.
|
||||
.Pp
|
||||
It is paramount to note that the file system may not remove the
|
||||
node data structures at this point, only the directory entry and prevent
|
||||
lookups from finding the node again.
|
||||
This is to retain the
|
||||
.Ux
|
||||
open file semantics.
|
||||
The data may be removed only when
|
||||
.Fn puffs_node_reclaim
|
||||
or
|
||||
.Fn puffs_node_reclaim2
|
||||
is called for the node, as this assures there are no further users.
|
||||
.It Fn puffs_node_link "pu" "opc" "targ" "pcn"
|
||||
Create a hard link for the node
|
||||
.Fa targ
|
||||
into the directory
|
||||
.Fa opc .
|
||||
The argument
|
||||
.Fa pcn
|
||||
provides the directory entry name for the new link.
|
||||
.It Fn puffs_node_rename "pu" "src_dir" "src" "pcn_src" "targ_dir" "targ" "pcn_targ"
|
||||
Rename the node
|
||||
.Fa src
|
||||
with the name specified by
|
||||
.Fa pcn_src
|
||||
from the directory
|
||||
.Fa src_dir .
|
||||
The target directory and target name are given by
|
||||
.Fa targ_dir
|
||||
and
|
||||
.Fa pcn_targ ,
|
||||
respectively.
|
||||
.Em If
|
||||
the target node already exists, it is specified by
|
||||
.Fa targ
|
||||
and must be replaced atomically.
|
||||
Otherwise
|
||||
.Fa targ
|
||||
is gives as
|
||||
.Dv NULL .
|
||||
.Pp
|
||||
It is legal to replace a directory node by another directory node with
|
||||
the means of rename if the target directory is empty, otherwise
|
||||
.Er ENOTEMPTY
|
||||
should be returned.
|
||||
All other types can replace all other types.
|
||||
In case a rename between incompatible types is attempted, the errors
|
||||
.Er ENOTDIR
|
||||
or
|
||||
.Er EISDIR
|
||||
should be returned, depending on the target type.
|
||||
.It Fn puffs_node_readdir "pu" "opc" "dent" "readoff" "reslen" "pcr" "eofflag" "cookies" "ncookies"
|
||||
To read directory entries,
|
||||
.Fn puffs_node_readdir
|
||||
is called.
|
||||
It should store directories as
|
||||
.Va struct dirent
|
||||
in the space pointed to by
|
||||
.Fa dent .
|
||||
The amount of space available is given by
|
||||
.Fa reslen
|
||||
and before returning it should be set to the amount of space
|
||||
.Em remaining
|
||||
in the buffer.
|
||||
The argument
|
||||
.Fa offset
|
||||
is used to specify the offset to the directory.
|
||||
Its intepretation is up to the file system and it should be set to
|
||||
signal the continuation point when there is no more room for the next
|
||||
entry in
|
||||
.Fa dent .
|
||||
It is most performant to return the maximal amount of directory
|
||||
entries each call.
|
||||
It is easiest to generate directory entries by using
|
||||
.Fn puffs_nextdent ,
|
||||
which also automatically advances the necessary pointers.
|
||||
.Pp
|
||||
In case end-of-directory is reached,
|
||||
.Fa eofflag
|
||||
should be set to one.
|
||||
Note that even a new call to readdir may start where
|
||||
.Fa readoff
|
||||
points to end-of-directory.
|
||||
.Pp
|
||||
If the file system supports file handles, the arguments
|
||||
.Fa cookies
|
||||
and
|
||||
.Fa ncookies
|
||||
must be filled out.
|
||||
.Fa cookies
|
||||
is a vector for offsets corresponding to read offsets.
|
||||
One cookie should be filled out for each directory entry.
|
||||
The value of the cookie should equal the offset of the
|
||||
.Em next
|
||||
directory entry, i.e., which offset should be passed to readdir for
|
||||
the first entry read to be the entry following the current one.
|
||||
.Fa ncookies
|
||||
is the number of slots for cookies in the cookie vector upon entry to
|
||||
the function and must be set to the amount of cookies stored in the
|
||||
vector (i.e., amount of directory entries read) upon exit.
|
||||
There is always enough space in the cookie vector for the maximal number
|
||||
of entries that will fit into the directory entry buffer.
|
||||
For filling out the vector, the helper function
|
||||
.Fn PUFFS_STORE_DCOOKIE cookies ncookies offset
|
||||
can be used.
|
||||
This properly checks against
|
||||
.Fa cookies
|
||||
being
|
||||
.Dv NULL .
|
||||
Note that
|
||||
.Fa ncookies
|
||||
must be initialized to zero before the first call to
|
||||
.Fn PUFFS_STORE_DCOOKIE .
|
||||
.It Fn puffs_node_symlink "pu" "opc" "pni" "pcn_src" "va" "link_target"
|
||||
Create a symbolic link into the directory
|
||||
.Fa opc
|
||||
with the name in
|
||||
.Fa pcn_src
|
||||
and the initial attributes in
|
||||
.Fa va .
|
||||
The argument
|
||||
.Ar link_target
|
||||
contains a null-terminated string for the link target.
|
||||
The created node cookie should be set in
|
||||
.Fa pni .
|
||||
.It Fn puffs_node_readlink "pu" "opc" "pcr" "link" "linklen"
|
||||
Read the target of a symbolic link
|
||||
.Fa opc .
|
||||
The result is placed in the buffer pointed to by
|
||||
.Fa link .
|
||||
This buffer's length is given in
|
||||
.Fa linklen
|
||||
and it must be updated to reflect the real link length.
|
||||
A terminating nul character should not be put into the buffer and
|
||||
.Em "must not"
|
||||
be included in the link length.
|
||||
.It Fn puffs_node_read "pu" "opc" "buf" "offset" "resid" "pcr" "ioflag"
|
||||
Read the contents of a file
|
||||
.Fa opc .
|
||||
It will gather the data from
|
||||
.Fa offset
|
||||
in the file and read the number
|
||||
.Fa resid
|
||||
octets.
|
||||
The buffer is guaranteed to have this much space.
|
||||
The amount of data requested by
|
||||
.Fa resid
|
||||
should be read, except in the case of eof-of-file or an error.
|
||||
The parameter
|
||||
.Fa resid
|
||||
should be set to indicate the amount of request NOT completed.
|
||||
In the normal case this should be 0.
|
||||
.It Fn puffs_node_write "pu" "opc" "buf" "offset" "resid" "pcr" "ioflag"
|
||||
.It Fn puffs_node_write2 "pu" "opc" "buf" "offset" "resid" "pcr" "ioflag" \
|
||||
"xflag"
|
||||
.Fn puffs_node_write
|
||||
writes data to a file
|
||||
.Fa opc
|
||||
at
|
||||
.Fa offset
|
||||
and extend the file if necessary.
|
||||
The number of octets written is indicated by
|
||||
.Fa resid ;
|
||||
everything must be written or an error will be generated.
|
||||
The parameter must be set to indicate the amount of data NOT written.
|
||||
In case the ioflag
|
||||
.Dv PUFFS_IO_APPEND
|
||||
is specified, the data should be appended to the end of the file.
|
||||
.Fn puffs_node_write2
|
||||
serves the same purpose as
|
||||
.Fn puffs_node_write
|
||||
with an additional
|
||||
.Fa xflag
|
||||
in which
|
||||
.Dv PUFFS_WRITE_FAF
|
||||
is set for Fire-And-Forget operations.
|
||||
.It Fn puffs_node_fallocate "pu" "opc" "pos" "len"
|
||||
Allocate
|
||||
.Fa len
|
||||
bytes of backing store at offset
|
||||
.Fa pos
|
||||
for the node referenced by the cookie
|
||||
.Fa opc .
|
||||
.It Fn puffs_node_fdiscard "pu" "opc" "pos" "len"
|
||||
Free
|
||||
.Fa len
|
||||
bytes of backing store (creating a hole) at offset
|
||||
.Fa pos
|
||||
for the node referenced by the cookie
|
||||
.Fa opc .
|
||||
.It Fn puffs_node_print "pu" "opc"
|
||||
Print information about node.
|
||||
This is used only for kernel-initiated diagnostic purposes.
|
||||
.It Fn puffs_node_reclaim "pu" "opc"
|
||||
The kernel will no longer reference the cookie and resources associated
|
||||
with it may be freed.
|
||||
In case the file
|
||||
.Fa opc
|
||||
has a link count of zero, it may be safely removed now.
|
||||
.It Fn puffs_node_reclaim2 "pu" "opc" "nlookup"
|
||||
Same as
|
||||
.Fn puffs_node_reclaim
|
||||
with an addditional argument for the number of lookups that have been done
|
||||
on the node (Node creation is counted as a lookup). This can be used by the
|
||||
file system to avoid a race condition, where the kernel sends a reclaim
|
||||
while it does not have received the reply for a lookup.
|
||||
If the file system tracks lookup count, and compares to
|
||||
.Fa nlookup
|
||||
it can detect this situation and ignore the reclaim.
|
||||
.Pp
|
||||
If the file system maps cookies to
|
||||
.Vt struct puffs_node
|
||||
then the framework will do that work, and
|
||||
.Fn puffs_node_reclaim
|
||||
can be reliabily used without the race condition.
|
||||
.It Fn puffs_node_abortop "pu" "opc" "pcn"
|
||||
In case the operation following lookup (e.g., mkdir or remove) is not
|
||||
executed for some reason, abortop will be issued.
|
||||
This is useful only for servers which cache state between lookup
|
||||
and a directory operation and is generally left unimplemented.
|
||||
.It Fn puffs_node_inactive "pu" "opc"
|
||||
The node
|
||||
.Fa opc
|
||||
has lost its last reference in the kernel.
|
||||
However, the cookie must still remain valid until
|
||||
.Fn puffs_node_reclaim
|
||||
or
|
||||
.Fn puffs_node_reclaim2
|
||||
is called.
|
||||
.It Fn puffs_setback "pcc" "op"
|
||||
Issue a "setback" operation which will be handled when the request response
|
||||
is returned to the kernel.
|
||||
Currently this can be only called from mmap, open, remove and rmdir.
|
||||
The valid parameters for
|
||||
.Ar op
|
||||
are
|
||||
.Dv PUFFS_SETBACK_INACT_N1
|
||||
and
|
||||
.Dv PUFFS_SETBACK_INACT_N2 .
|
||||
These signal that a file system mounted with
|
||||
.Dv PUFFS_KFLAG_IAONDEMAND
|
||||
should call the file system inactive method for the specified node.
|
||||
The node number 1 always means the operation cookie
|
||||
.Ar opc ,
|
||||
while the node number 2 can be used to specify the second node argument
|
||||
present in some methods, e.g., remove.
|
||||
.It Fn puffs_newinfo_setcookie pni cookie
|
||||
Set cookie for node provided by this method to
|
||||
.Ar cookie .
|
||||
.It Fn puffs_newinfo_setvtype pni vtype
|
||||
Set the type of the newly located node to
|
||||
.Ar vtype .
|
||||
This call is valid only for
|
||||
.Fn lookup
|
||||
and
|
||||
.Fn fhtonode .
|
||||
.It Fn puffs_newinfo_setsize pni size
|
||||
Set the size of the newly located node to
|
||||
.Ar size .
|
||||
If left unset, the value defaults to 0.
|
||||
This call is valid only for
|
||||
.Fn lookup
|
||||
and
|
||||
.Fn fhtovp .
|
||||
.It Fn puffs_newinfo_setrdev pni rdev
|
||||
Set the type of the newly located node to
|
||||
.Ar vtype .
|
||||
This call is valid only for
|
||||
.Fn lookup
|
||||
and
|
||||
.Fn fhtovp
|
||||
producing device type nodes.
|
||||
.It Fn puffs_newinfo_setva pni vap
|
||||
Set the attributes for newly created vnode.
|
||||
This call is valid for
|
||||
.Fn lookup ,
|
||||
.Fn create ,
|
||||
.Fn mkdir ,
|
||||
.Fn mknod ,
|
||||
and
|
||||
.Fn symlink ,
|
||||
if
|
||||
.Fn puffs_init
|
||||
was called with
|
||||
.Dv PUFFS_KFLAG_CACHE_FS_TTL
|
||||
flag set.
|
||||
.It Fn puffs_newinfo_setvattl pni va_ttl
|
||||
Set cached attribute time to live for newly created vnode.
|
||||
This call is valid for
|
||||
.Fn lookup ,
|
||||
.Fn create ,
|
||||
.Fn mkdir ,
|
||||
.Fn mknod ,
|
||||
and
|
||||
.Fn symlink ,
|
||||
if
|
||||
.Fn puffs_init
|
||||
was called with
|
||||
.Dv PUFFS_KFLAG_CACHE_FS_TTL
|
||||
flag set.
|
||||
.It Fn puffs_newinfo_setcnttl pni cn_ttl
|
||||
Set cached name time to live for newly created vnode.
|
||||
This call is valid for
|
||||
.Fn lookup ,
|
||||
.Fn create ,
|
||||
.Fn mkdir ,
|
||||
.Fn mknod ,
|
||||
and
|
||||
.Fn symlink ,
|
||||
if
|
||||
.Fn puffs_init
|
||||
was called with
|
||||
.Dv PUFFS_KFLAG_CACHE_FS_TTL
|
||||
flag set.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr vfsops 9 ,
|
||||
.Xr vnodeops 9
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
.\" $NetBSD: puffs_path.3,v 1.4 2009/02/20 14:26:56 pooka Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Antti Kantee. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd December 27, 2007
|
||||
.Dt PUFFS_PATH 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm puffs_path
|
||||
.Nd puffs pathbuilding routines
|
||||
.Sh LIBRARY
|
||||
.Lb libpuffs
|
||||
.Sh SYNOPSIS
|
||||
.In puffs.h
|
||||
.Ft int
|
||||
.Fo pu_pathbuild_fn
|
||||
.Fa "struct puffs_usermount *pu" "const struct puffs_pathobj *po_dir"
|
||||
.Fa "const struct puffs_pathobj *po_comp" "size_t offset"
|
||||
.Fa "struct puffs_pathobj *po_new"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo pu_pathtransform_fn
|
||||
.Fa "struct puffs_usermount *pu" "const struct puffs_pathobj *po_base"
|
||||
.Fa "const struct puffs_cn *pcn" "struct puffs_pathobj *po_new"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fo pu_pathcmp_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_pathobj *po1"
|
||||
.Fa "struct puffs_pathobj *po2" "size_t checklen" "int checkprefix"
|
||||
.Fc
|
||||
.Ft void
|
||||
.Fn pu_pathfree_fn "struct puffs_usermount *pu" "struct puffs_pathobj *po"
|
||||
.Ft int
|
||||
.Fo pu_namemod_fn
|
||||
.Fa "struct puffs_usermount *pu" "struct puffs_pathobj *po_dir"
|
||||
.Fa "struct puffs_cn *pcn"
|
||||
.Fc
|
||||
.Ft struct puffs_pathobj *
|
||||
.Fn puffs_getrootpathobj "struct puffs_usermount *pu"
|
||||
.Sh DESCRIPTION
|
||||
The puffs library has the ability to provide full pathnames for backends
|
||||
which require them.
|
||||
Normal file systems should be constructed without the file system
|
||||
node tied to a file name and should not used routines described herein.
|
||||
An example of a file system where the backend requires filenames is
|
||||
.Xr mount_psshfs 8 .
|
||||
.Pp
|
||||
The features described here are enabled by passing
|
||||
.Dv PUFFS_FLAG_BUILDPATH
|
||||
to
|
||||
.Fn puffs_init .
|
||||
This facility requires to use puffs nodes to store the contents of the
|
||||
pathname.
|
||||
Either the address of the operation cookie must directly be that of the
|
||||
puffs node, or
|
||||
.Fn puffs_set_cmap
|
||||
must be used to set a mapping function from the cookie to the puffs
|
||||
node associated with the cookie.
|
||||
Finally, the root node for the file system must be set using
|
||||
.Fn puffs_setroot
|
||||
and the root path object retrieved using
|
||||
.Fn puffs_getrootpathobj
|
||||
and initialized.
|
||||
.Pp
|
||||
There are two different places a filename can be retrieved from.
|
||||
It is available for each puffs node after the node has been registered
|
||||
with the framework, i.e.
|
||||
.Em after
|
||||
the routine creating the node returns.
|
||||
In other words, there is a window between the node is created and
|
||||
when the pathname is available and multithreaded file systems must
|
||||
take this into account.
|
||||
The second place where a pathname is available is from the componentname
|
||||
.Vt struct puffs_pcn
|
||||
in operations which are passed one.
|
||||
These can be retrieved using the convenience macros
|
||||
.Fn PNPATH
|
||||
and
|
||||
.Fn PCNPATH
|
||||
for node and componentname, respectively.
|
||||
The type of object they return is
|
||||
.Vt void * .
|
||||
.Pp
|
||||
By default the framework manages "regular" filenames, which consist
|
||||
of directory names separated by "/" and a final component.
|
||||
If the file system wishes to use pathnames of this format, all it
|
||||
has to do it enable the feature.
|
||||
Everything else, including bookkeeping for node and directory renames,
|
||||
is done by the library.
|
||||
The callback routines described next provide the ability to build
|
||||
non-standard pathnames.
|
||||
A
|
||||
.Fn pu_foo_fn
|
||||
callback is set using the
|
||||
.Fn puffs_set_foo
|
||||
routine.
|
||||
.Pp
|
||||
This manual page is still unfinished.
|
||||
Please take a number and wait in line.
|
||||
.Sh SEE ALSO
|
||||
.Xr puffs 3 ,
|
||||
.Xr puffs_node 3 ,
|
||||
.Xr mount_psshfs 8 ,
|
||||
.Xr mount_sysctlfs 8
|
||||
|
|
@ -1,278 +0,0 @@
|
|||
/* $NetBSD: puffs_priv.h,v 1.45 2012/04/18 00:57:22 manu Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007, 2008 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PUFFS_PRIVATE_H_
|
||||
#define _PUFFS_PRIVATE_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fs/puffs/puffs_msgif.h>
|
||||
|
||||
#if !defined(__minix)
|
||||
#include <pthread.h>
|
||||
#endif /* !defined(__minix) */
|
||||
#include <puffs.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#if !defined(__minix)
|
||||
extern pthread_mutex_t pu_lock;
|
||||
#define PU_LOCK() pthread_mutex_lock(&pu_lock)
|
||||
#define PU_UNLOCK() pthread_mutex_unlock(&pu_lock)
|
||||
#else
|
||||
#define PU_LOCK() /* nothing */
|
||||
#define PU_UNLOCK() /* nothing */
|
||||
#endif /* !defined(__minix) */
|
||||
|
||||
#define PU_CMAP(pu, c) (pu->pu_cmap ? pu->pu_cmap(pu,c) : (struct puffs_node*)c)
|
||||
|
||||
struct puffs_framectrl {
|
||||
puffs_framev_readframe_fn rfb;
|
||||
puffs_framev_writeframe_fn wfb;
|
||||
puffs_framev_cmpframe_fn cmpfb;
|
||||
puffs_framev_gotframe_fn gotfb;
|
||||
puffs_framev_fdnotify_fn fdnotfn;
|
||||
};
|
||||
|
||||
struct puffs_fctrl_io {
|
||||
struct puffs_framectrl *fctrl;
|
||||
|
||||
int io_fd;
|
||||
int stat;
|
||||
|
||||
int rwait;
|
||||
int wwait;
|
||||
|
||||
struct puffs_framebuf *cur_in;
|
||||
|
||||
TAILQ_HEAD(, puffs_framebuf) snd_qing; /* queueing to be sent */
|
||||
TAILQ_HEAD(, puffs_framebuf) res_qing; /* q'ing for rescue */
|
||||
LIST_HEAD(, puffs_fbevent) ev_qing; /* q'ing for events */
|
||||
|
||||
LIST_ENTRY(puffs_fctrl_io) fio_entries;
|
||||
};
|
||||
#define FIO_WR 0x01
|
||||
#define FIO_WRGONE 0x02
|
||||
#define FIO_RDGONE 0x04
|
||||
#define FIO_DEAD 0x08
|
||||
#define FIO_ENABLE_R 0x10
|
||||
#define FIO_ENABLE_W 0x20
|
||||
|
||||
#define FIO_EN_WRITE(fio) \
|
||||
(!(fio->stat & FIO_WR) \
|
||||
&& ((!TAILQ_EMPTY(&fio->snd_qing) \
|
||||
&& (fio->stat & FIO_ENABLE_W)) \
|
||||
|| fio->wwait))
|
||||
|
||||
#define FIO_RM_WRITE(fio) \
|
||||
((fio->stat & FIO_WR) \
|
||||
&& (((TAILQ_EMPTY(&fio->snd_qing) \
|
||||
|| (fio->stat & FIO_ENABLE_W) == 0)) \
|
||||
&& (fio->wwait == 0)))
|
||||
|
||||
|
||||
/*
|
||||
* usermount: describes one file system instance
|
||||
*/
|
||||
struct puffs_usermount {
|
||||
struct puffs_ops pu_ops;
|
||||
|
||||
int pu_fd;
|
||||
size_t pu_maxreqlen;
|
||||
|
||||
uint32_t pu_flags;
|
||||
int pu_cc_stackshift;
|
||||
|
||||
ucontext_t pu_mainctx;
|
||||
#define PUFFS_CCMAXSTORE 32
|
||||
int pu_cc_nstored;
|
||||
|
||||
int pu_kq;
|
||||
int pu_state;
|
||||
#define PU_STATEMASK 0x00ff
|
||||
#define PU_INLOOP 0x0100
|
||||
#define PU_ASYNCFD 0x0200
|
||||
#define PU_HASKQ 0x0400
|
||||
#define PU_PUFFSDAEMON 0x0800
|
||||
#define PU_MAINRESTORE 0x1000
|
||||
#define PU_DONEXIT 0x2000
|
||||
#define PU_SETSTATE(pu, s) (pu->pu_state = (s) | (pu->pu_state & ~PU_STATEMASK))
|
||||
#define PU_SETSFLAG(pu, s) (pu->pu_state |= (s))
|
||||
#define PU_CLRSFLAG(pu, s) \
|
||||
(pu->pu_state = ((pu->pu_state & ~(s)) | (pu->pu_state & PU_STATEMASK)))
|
||||
int pu_dpipe[2];
|
||||
|
||||
struct puffs_node *pu_pn_root;
|
||||
|
||||
LIST_HEAD(, puffs_node) pu_pnodelst;
|
||||
#if defined(__minix)
|
||||
LIST_HEAD(, puffs_node) pu_pnode_removed_lst;
|
||||
#endif /* defined(__minix) */
|
||||
|
||||
LIST_HEAD(, puffs_cc) pu_ccmagazin;
|
||||
TAILQ_HEAD(, puffs_cc) pu_lazyctx;
|
||||
TAILQ_HEAD(, puffs_cc) pu_sched;
|
||||
|
||||
pu_cmap_fn pu_cmap;
|
||||
|
||||
pu_pathbuild_fn pu_pathbuild;
|
||||
pu_pathtransform_fn pu_pathtransform;
|
||||
pu_pathcmp_fn pu_pathcmp;
|
||||
pu_pathfree_fn pu_pathfree;
|
||||
pu_namemod_fn pu_namemod;
|
||||
|
||||
pu_errnotify_fn pu_errnotify;
|
||||
|
||||
pu_prepost_fn pu_oppre;
|
||||
pu_prepost_fn pu_oppost;
|
||||
|
||||
struct puffs_framectrl pu_framectrl[2];
|
||||
#define PU_FRAMECTRL_FS 0
|
||||
#define PU_FRAMECTRL_USER 1
|
||||
LIST_HEAD(, puffs_fctrl_io) pu_ios;
|
||||
LIST_HEAD(, puffs_fctrl_io) pu_ios_rmlist;
|
||||
struct kevent *pu_evs;
|
||||
size_t pu_nevs;
|
||||
|
||||
puffs_ml_loop_fn pu_ml_lfn;
|
||||
struct timespec pu_ml_timeout;
|
||||
struct timespec *pu_ml_timep;
|
||||
|
||||
struct puffs_kargs *pu_kargp;
|
||||
|
||||
uint64_t pu_nextreq;
|
||||
void *pu_privdata;
|
||||
};
|
||||
|
||||
/* call context */
|
||||
|
||||
struct puffs_cc;
|
||||
typedef void (*puffs_ccfunc)(struct puffs_cc *);
|
||||
|
||||
struct puffs_cc {
|
||||
struct puffs_usermount *pcc_pu;
|
||||
struct puffs_framebuf *pcc_pb;
|
||||
|
||||
/* real cc */
|
||||
union {
|
||||
struct {
|
||||
ucontext_t uc; /* "continue" */
|
||||
ucontext_t uc_ret; /* "yield" */
|
||||
} real;
|
||||
struct {
|
||||
puffs_ccfunc func;
|
||||
void *farg;
|
||||
} fake;
|
||||
} pcc_u;
|
||||
|
||||
pid_t pcc_pid;
|
||||
lwpid_t pcc_lid;
|
||||
|
||||
int pcc_flags;
|
||||
|
||||
TAILQ_ENTRY(puffs_cc) pcc_schedent;
|
||||
LIST_ENTRY(puffs_cc) pcc_rope;
|
||||
};
|
||||
#define pcc_uc pcc_u.real.uc
|
||||
#define pcc_uc_ret pcc_u.real.uc_ret
|
||||
#define pcc_func pcc_u.fake.func
|
||||
#define pcc_farg pcc_u.fake.farg
|
||||
#define PCC_DONE 0x01
|
||||
#define PCC_BORROWED 0x02
|
||||
#define PCC_HASCALLER 0x04
|
||||
#define PCC_MLCONT 0x08
|
||||
|
||||
struct puffs_newinfo {
|
||||
void **pni_cookie;
|
||||
enum vtype *pni_vtype;
|
||||
voff_t *pni_size;
|
||||
dev_t *pni_rdev;
|
||||
struct vattr *pni_va;
|
||||
struct timespec *pni_va_ttl;
|
||||
struct timespec *pni_cn_ttl;
|
||||
};
|
||||
|
||||
#define PUFFS_MAKEKCRED(to, from) \
|
||||
/*LINTED: tnilxnaht, the cast is ok */ \
|
||||
const struct puffs_kcred *to = (const void *)from
|
||||
#define PUFFS_MAKECRED(to, from) \
|
||||
/*LINTED: tnilxnaht, the cast is ok */ \
|
||||
const struct puffs_cred *to = (const void *)from
|
||||
#define PUFFS_KCREDTOCRED(to, from) \
|
||||
/*LINTED: tnilxnaht, the cast is ok */ \
|
||||
to = (void *)from
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void puffs__framev_input(struct puffs_usermount *, struct puffs_framectrl *,
|
||||
struct puffs_fctrl_io *);
|
||||
int puffs__framev_output(struct puffs_usermount *, struct puffs_framectrl*,
|
||||
struct puffs_fctrl_io *);
|
||||
void puffs__framev_exit(struct puffs_usermount *);
|
||||
void puffs__framev_readclose(struct puffs_usermount *,
|
||||
struct puffs_fctrl_io *, int);
|
||||
void puffs__framev_writeclose(struct puffs_usermount *,
|
||||
struct puffs_fctrl_io *, int);
|
||||
void puffs__framev_notify(struct puffs_fctrl_io *, int);
|
||||
void *puffs__framebuf_getdataptr(struct puffs_framebuf *);
|
||||
int puffs__framev_addfd_ctrl(struct puffs_usermount *, int, int,
|
||||
struct puffs_framectrl *);
|
||||
void puffs__framebuf_moveinfo(struct puffs_framebuf *,
|
||||
struct puffs_framebuf *);
|
||||
|
||||
void puffs__theloop(struct puffs_cc *);
|
||||
void puffs__ml_dispatch(struct puffs_usermount *, struct puffs_framebuf *);
|
||||
|
||||
int puffs__cc_create(struct puffs_usermount *, puffs_ccfunc,
|
||||
struct puffs_cc **);
|
||||
void puffs__cc_cont(struct puffs_cc *);
|
||||
void puffs__cc_destroy(struct puffs_cc *, int);
|
||||
void puffs__cc_setcaller(struct puffs_cc *, pid_t, lwpid_t);
|
||||
void puffs__goto(struct puffs_cc *);
|
||||
int puffs__cc_savemain(struct puffs_usermount *);
|
||||
int puffs__cc_restoremain(struct puffs_usermount *);
|
||||
void puffs__cc_exit(struct puffs_usermount *);
|
||||
|
||||
int puffs__fsframe_read(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs__fsframe_write(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
int, int *);
|
||||
int puffs__fsframe_cmp(struct puffs_usermount *, struct puffs_framebuf *,
|
||||
struct puffs_framebuf *, int *);
|
||||
void puffs__fsframe_gotframe(struct puffs_usermount *,
|
||||
struct puffs_framebuf *);
|
||||
|
||||
uint64_t puffs__nextreq(struct puffs_usermount *pu);
|
||||
|
||||
#if defined(__minix)
|
||||
int lpuffs_pump(void);
|
||||
void lpuffs_init(struct puffs_usermount *);
|
||||
void lpuffs_debug(const char *format, ...)
|
||||
__attribute__((__format__(__printf__, 1, 2)));
|
||||
#endif /* defined(__minix) */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _PUFFS_PRIVATE_H_ */
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/* $NetBSD: puffsdump.h,v 1.15 2010/07/11 12:29:08 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the Ulla Tuominen Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PUFFSDUMP_H_
|
||||
#define _PUFFSDUMP_H_
|
||||
|
||||
/*
|
||||
* Note for callers outside of libpuffs: these are to be used only
|
||||
* for debug builds. Interfaces are not guaranteed to remain stable.
|
||||
*/
|
||||
|
||||
#include <fs/puffs/puffs_msgif.h>
|
||||
|
||||
void puffsdump_req(struct puffs_req *);
|
||||
void puffsdump_rv(struct puffs_req *);
|
||||
void puffsdump_cookie(puffs_cookie_t, const char *);
|
||||
void puffsdump_cn(struct puffs_kcn *);
|
||||
|
||||
void puffsdump_readwrite(struct puffs_req *);
|
||||
void puffsdump_readwrite_rv(struct puffs_req *);
|
||||
void puffsdump_readdir(struct puffs_req *);
|
||||
void puffsdump_readdir_rv(struct puffs_req *);
|
||||
void puffsdump_lookup(struct puffs_req *);
|
||||
void puffsdump_lookup_rv(struct puffs_req *);
|
||||
void puffsdump_create(struct puffs_req *);
|
||||
void puffsdump_create_rv(struct puffs_req *);
|
||||
void puffsdump_open(struct puffs_req *);
|
||||
|
||||
void puffsdump_attr(struct puffs_req *);
|
||||
void puffsdump_targ(struct puffs_req *);
|
||||
|
||||
extern const char *puffsdump_vfsop_revmap[];
|
||||
extern const char *puffsdump_vnop_revmap[];
|
||||
extern const char *puffsdump_errnot_revmap[];
|
||||
extern const char *puffsdump_flush_revmap[];
|
||||
|
||||
extern size_t puffsdump_vfsop_count;
|
||||
extern size_t puffsdump_vnop_count;
|
||||
extern size_t puffsdump_errnot_count;
|
||||
extern size_t puffsdump_flush_count;
|
||||
|
||||
#endif /* _PUFFSDUMP_H_ */
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
/* $NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Development of this software was supported by the
|
||||
* Research Foundation of Helsinki University of Technology
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: requests.c,v 1.24 2013/01/23 20:22:34 riastradh Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <dev/putter/putter.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
/*
|
||||
* Read a frame from the upstream provider. First read the frame
|
||||
* length and after this read the actual contents. Yes, optimize
|
||||
* me some day.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs__fsframe_read(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
int fd, int *done)
|
||||
{
|
||||
struct putter_hdr phdr;
|
||||
void *win;
|
||||
size_t howmuch, winlen, curoff;
|
||||
ssize_t n;
|
||||
int lenstate;
|
||||
|
||||
/* How much to read? */
|
||||
the_next_level:
|
||||
curoff = puffs_framebuf_telloff(pb);
|
||||
if (curoff < sizeof(struct putter_hdr)) {
|
||||
howmuch = sizeof(struct putter_hdr) - curoff;
|
||||
lenstate = 1;
|
||||
} else {
|
||||
puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
|
||||
/*LINTED*/
|
||||
howmuch = phdr.pth_framelen - curoff;
|
||||
lenstate = 0;
|
||||
}
|
||||
|
||||
if (puffs_framebuf_reserve_space(pb, howmuch) == -1)
|
||||
return errno;
|
||||
|
||||
/* Read contents */
|
||||
while (howmuch) {
|
||||
winlen = howmuch;
|
||||
curoff = puffs_framebuf_telloff(pb);
|
||||
if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
|
||||
return errno;
|
||||
n = read(fd, win, winlen);
|
||||
switch (n) {
|
||||
case 0:
|
||||
return ECONNRESET;
|
||||
case -1:
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
return errno;
|
||||
default:
|
||||
howmuch -= n;
|
||||
puffs_framebuf_seekset(pb, curoff + n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (lenstate)
|
||||
goto the_next_level;
|
||||
|
||||
puffs_framebuf_seekset(pb, 0);
|
||||
*done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a frame upstream
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs__fsframe_write(struct puffs_usermount *pu, struct puffs_framebuf *pb,
|
||||
int fd, int *done)
|
||||
{
|
||||
void *win;
|
||||
uint64_t flen;
|
||||
size_t winlen, howmuch, curoff;
|
||||
ssize_t n;
|
||||
int rv;
|
||||
|
||||
/*
|
||||
* Finalize it if we haven't written anything yet (or we're still
|
||||
* attempting to write the first byte)
|
||||
*
|
||||
* XXX: this shouldn't be here
|
||||
*/
|
||||
if (puffs_framebuf_telloff(pb) == 0) {
|
||||
struct puffs_req *preq;
|
||||
|
||||
winlen = sizeof(struct puffs_req);
|
||||
rv = puffs_framebuf_getwindow(pb, 0, (void *)&preq, &winlen);
|
||||
if (rv == -1)
|
||||
return errno;
|
||||
preq->preq_pth.pth_framelen = flen = preq->preq_buflen;
|
||||
} else {
|
||||
struct putter_hdr phdr;
|
||||
|
||||
puffs_framebuf_getdata_atoff(pb, 0, &phdr, sizeof(phdr));
|
||||
flen = phdr.pth_framelen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then write it. Chances are if we are talking to the kernel it'll
|
||||
* just shlosh in all at once, but if we're e.g. talking to the
|
||||
* network it might take a few tries.
|
||||
*/
|
||||
/*LINTED*/
|
||||
howmuch = flen - puffs_framebuf_telloff(pb);
|
||||
|
||||
while (howmuch) {
|
||||
winlen = howmuch;
|
||||
curoff = puffs_framebuf_telloff(pb);
|
||||
if (puffs_framebuf_getwindow(pb, curoff, &win, &winlen) == -1)
|
||||
return errno;
|
||||
|
||||
/*
|
||||
* XXX: we know from the framebuf implementation that we
|
||||
* will always managed to map the entire window. But if
|
||||
* that changes, this will catch it. Then we can do stuff
|
||||
* iov stuff instead.
|
||||
*/
|
||||
assert(winlen == howmuch);
|
||||
|
||||
/* XXX: want NOSIGNAL if writing to a pipe */
|
||||
#if 0
|
||||
n = send(fd, win, winlen, MSG_NOSIGNAL);
|
||||
#else
|
||||
n = write(fd, win, winlen);
|
||||
#endif
|
||||
switch (n) {
|
||||
case 0:
|
||||
return ECONNRESET;
|
||||
case -1:
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
return errno;
|
||||
default:
|
||||
howmuch -= n;
|
||||
puffs_framebuf_seekset(pb, curoff + n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare if "pb1" is a response to a previously sent frame pb2.
|
||||
* More often than not "pb1" is not a response to anything but
|
||||
* rather a fresh request from the kernel.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs__fsframe_cmp(struct puffs_usermount *pu,
|
||||
struct puffs_framebuf *pb1, struct puffs_framebuf *pb2, int *notresp)
|
||||
{
|
||||
struct puffs_req *preq1, *preq2;
|
||||
size_t winlen;
|
||||
int rv;
|
||||
|
||||
/* map incoming preq */
|
||||
winlen = sizeof(struct puffs_req);
|
||||
rv = puffs_framebuf_getwindow(pb1, 0, (void *)&preq1, &winlen);
|
||||
assert(rv == 0); /* frames are always at least puffs_req in size */
|
||||
assert(winlen == sizeof(struct puffs_req));
|
||||
|
||||
/*
|
||||
* Check if this is not a response in this slot. That's the
|
||||
* likely case.
|
||||
*/
|
||||
if ((preq1->preq_opclass & PUFFSOPFLAG_ISRESPONSE) == 0) {
|
||||
*notresp = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* map second preq */
|
||||
winlen = sizeof(struct puffs_req);
|
||||
rv = puffs_framebuf_getwindow(pb2, 0, (void *)&preq2, &winlen);
|
||||
assert(rv == 0); /* frames are always at least puffs_req in size */
|
||||
assert(winlen == sizeof(struct puffs_req));
|
||||
|
||||
/* then compare: resid equal? */
|
||||
return preq1->preq_id != preq2->preq_id;
|
||||
}
|
||||
|
||||
void
|
||||
puffs__fsframe_gotframe(struct puffs_usermount *pu, struct puffs_framebuf *pb)
|
||||
{
|
||||
|
||||
puffs_framebuf_seekset(pb, 0);
|
||||
puffs__ml_dispatch(pu, pb);
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# $NetBSD: shlib_version,v 1.5 2010/05/21 10:50:52 pooka Exp $
|
||||
#
|
||||
major=2
|
||||
minor=0
|
||||
|
|
@ -1,321 +0,0 @@
|
|||
/* $NetBSD: subr.c,v 1.27 2011/02/17 17:55:36 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: subr.c,v 1.27 2011/02/17 17:55:36 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "puffs_priv.h"
|
||||
|
||||
int
|
||||
puffs_gendotdent(struct dirent **dent, ino_t id, int dotdot, size_t *reslen)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
assert(dotdot == 0 || dotdot == 1);
|
||||
name = dotdot == 0 ? "." : "..";
|
||||
|
||||
return puffs_nextdent(dent, name, id, DT_DIR, reslen);
|
||||
}
|
||||
|
||||
int
|
||||
puffs_nextdent(struct dirent **dent, const char *name, ino_t id, uint8_t dtype,
|
||||
size_t *reslen)
|
||||
{
|
||||
struct dirent *d = *dent;
|
||||
|
||||
/* check if we have enough room for our dent-aligned dirent */
|
||||
if (_DIRENT_RECLEN(d, strlen(name)) > *reslen)
|
||||
return 0;
|
||||
|
||||
d->d_fileno = id;
|
||||
d->d_type = dtype;
|
||||
d->d_namlen = (uint16_t)strlen(name);
|
||||
(void)memcpy(&d->d_name, name, (size_t)d->d_namlen);
|
||||
d->d_name[d->d_namlen] = '\0';
|
||||
d->d_reclen = (uint16_t)_DIRENT_SIZE(d);
|
||||
|
||||
*reslen -= d->d_reclen;
|
||||
*dent = _DIRENT_NEXT(d);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsnop_unmount(struct puffs_usermount *dontuse1, int dontuse2)
|
||||
{
|
||||
|
||||
/* would you like to see puffs rule again, my friend? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsnop_sync(struct puffs_usermount *dontuse1, int dontuse2,
|
||||
const struct puffs_cred *dontuse3)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fsnop_statvfs(struct puffs_usermount *dontuse1, struct statvfs *sbp)
|
||||
{
|
||||
|
||||
sbp->f_bsize = sbp->f_frsize = sbp->f_iosize = DEV_BSIZE;
|
||||
|
||||
sbp->f_bfree=sbp->f_bavail=sbp->f_bresvd=sbp->f_blocks = (fsblkcnt_t)0;
|
||||
sbp->f_ffree=sbp->f_favail=sbp->f_fresvd=sbp->f_files = (fsfilcnt_t)0;
|
||||
|
||||
sbp->f_namemax = MAXNAMLEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*ARGSUSED3*/
|
||||
int
|
||||
puffs_genfs_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
|
||||
struct vattr *va, const struct puffs_cred *pcr)
|
||||
{
|
||||
struct puffs_node *pn = PU_CMAP(pu, opc);
|
||||
|
||||
memcpy(va, &pn->pn_va, sizeof(struct vattr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just put the node, don't do anything else. Don't use this if
|
||||
* your fs needs more cleanup.
|
||||
*/
|
||||
/*ARGSUSED2*/
|
||||
int
|
||||
puffs_genfs_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc)
|
||||
{
|
||||
|
||||
puffs_pn_put(PU_CMAP(pu, opc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just a wrapper to make calling the above nicer without having to pass
|
||||
* NULLs from application code
|
||||
*/
|
||||
void
|
||||
puffs_zerostatvfs(struct statvfs *sbp)
|
||||
{
|
||||
|
||||
puffs_fsnop_statvfs(NULL, sbp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set vattr values for those applicable (i.e. not PUFFS_VNOVAL).
|
||||
*/
|
||||
void
|
||||
puffs_setvattr(struct vattr *vap, const struct vattr *sva)
|
||||
{
|
||||
|
||||
#define SETIFVAL(a, t) if (sva->a != (t)PUFFS_VNOVAL) vap->a = sva->a
|
||||
if (sva->va_type != VNON)
|
||||
vap->va_type = sva->va_type;
|
||||
SETIFVAL(va_mode, mode_t);
|
||||
SETIFVAL(va_nlink, nlink_t);
|
||||
SETIFVAL(va_uid, uid_t);
|
||||
SETIFVAL(va_gid, gid_t);
|
||||
SETIFVAL(va_fsid, dev_t);
|
||||
SETIFVAL(va_size, u_quad_t);
|
||||
SETIFVAL(va_fileid, ino_t);
|
||||
SETIFVAL(va_blocksize, long);
|
||||
SETIFVAL(va_atime.tv_sec, time_t);
|
||||
SETIFVAL(va_ctime.tv_sec, time_t);
|
||||
SETIFVAL(va_mtime.tv_sec, time_t);
|
||||
SETIFVAL(va_birthtime.tv_sec, time_t);
|
||||
SETIFVAL(va_atime.tv_nsec, long);
|
||||
SETIFVAL(va_ctime.tv_nsec, long);
|
||||
SETIFVAL(va_mtime.tv_nsec, long);
|
||||
SETIFVAL(va_birthtime.tv_nsec, long);
|
||||
SETIFVAL(va_gen, u_long);
|
||||
SETIFVAL(va_flags, u_long);
|
||||
SETIFVAL(va_rdev, dev_t);
|
||||
SETIFVAL(va_bytes, u_quad_t);
|
||||
#undef SETIFVAL
|
||||
/* ignore va->va_vaflags */
|
||||
}
|
||||
|
||||
void
|
||||
puffs_vattr_null(struct vattr *vap)
|
||||
{
|
||||
|
||||
vap->va_type = VNON;
|
||||
|
||||
/*
|
||||
* Assign individually so that it is safe even if size and
|
||||
* sign of each member are varied.
|
||||
*/
|
||||
vap->va_mode = (mode_t)PUFFS_VNOVAL;
|
||||
vap->va_nlink = (nlink_t)PUFFS_VNOVAL;
|
||||
vap->va_uid = (uid_t)PUFFS_VNOVAL;
|
||||
vap->va_gid = (gid_t)PUFFS_VNOVAL;
|
||||
vap->va_fsid = (dev_t)PUFFS_VNOVAL;
|
||||
vap->va_fileid = (ino_t)PUFFS_VNOVAL;
|
||||
vap->va_size = (u_quad_t)PUFFS_VNOVAL;
|
||||
vap->va_blocksize = sysconf(_SC_PAGESIZE);
|
||||
vap->va_atime.tv_sec =
|
||||
vap->va_mtime.tv_sec =
|
||||
vap->va_ctime.tv_sec =
|
||||
vap->va_birthtime.tv_sec = PUFFS_VNOVAL;
|
||||
vap->va_atime.tv_nsec =
|
||||
vap->va_mtime.tv_nsec =
|
||||
vap->va_ctime.tv_nsec =
|
||||
vap->va_birthtime.tv_nsec = PUFFS_VNOVAL;
|
||||
vap->va_rdev = (dev_t)PUFFS_VNOVAL;
|
||||
vap->va_bytes = (u_quad_t)PUFFS_VNOVAL;
|
||||
|
||||
vap->va_flags = 0;
|
||||
vap->va_gen = 0;
|
||||
vap->va_vaflags = 0;
|
||||
}
|
||||
|
||||
static int vdmap[] = {
|
||||
DT_UNKNOWN, /* VNON */
|
||||
DT_REG, /* VREG */
|
||||
DT_DIR, /* VDIR */
|
||||
DT_BLK, /* VBLK */
|
||||
DT_CHR, /* VCHR */
|
||||
DT_LNK, /* VLNK */
|
||||
DT_SOCK, /* VSUCK*/
|
||||
DT_FIFO, /* VFIFO*/
|
||||
DT_UNKNOWN /* VBAD */
|
||||
};
|
||||
/* XXX: DT_WHT ? */
|
||||
int
|
||||
puffs_vtype2dt(enum vtype vt)
|
||||
{
|
||||
|
||||
if ((int)vt >= VNON && vt < (sizeof(vdmap)/sizeof(vdmap[0])))
|
||||
return vdmap[vt];
|
||||
|
||||
return DT_UNKNOWN;
|
||||
}
|
||||
|
||||
enum vtype
|
||||
puffs_mode2vt(mode_t mode)
|
||||
{
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFIFO:
|
||||
return VFIFO;
|
||||
case S_IFCHR:
|
||||
return VCHR;
|
||||
case S_IFDIR:
|
||||
return VDIR;
|
||||
case S_IFBLK:
|
||||
return VBLK;
|
||||
case S_IFREG:
|
||||
return VREG;
|
||||
case S_IFLNK:
|
||||
return VLNK;
|
||||
case S_IFSOCK:
|
||||
return VSOCK;
|
||||
default:
|
||||
return VBAD; /* XXX: not really true, but ... */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
puffs_stat2vattr(struct vattr *va, const struct stat *sb)
|
||||
{
|
||||
|
||||
va->va_type = puffs_mode2vt(sb->st_mode);
|
||||
va->va_mode = sb->st_mode;
|
||||
va->va_nlink = sb->st_nlink;
|
||||
va->va_uid = sb->st_uid;
|
||||
va->va_gid = sb->st_gid;
|
||||
va->va_fsid = sb->st_dev;
|
||||
va->va_fileid = sb->st_ino;
|
||||
va->va_size = sb->st_size;
|
||||
va->va_blocksize = sb->st_blksize;
|
||||
va->va_atime = sb->st_atimespec;
|
||||
va->va_ctime = sb->st_ctimespec;
|
||||
va->va_mtime = sb->st_mtimespec;
|
||||
va->va_birthtime = sb->st_birthtimespec;
|
||||
va->va_gen = sb->st_gen;
|
||||
va->va_flags = sb->st_flags;
|
||||
va->va_rdev = sb->st_rdev;
|
||||
va->va_bytes = sb->st_blocks << DEV_BSHIFT;
|
||||
va->va_filerev = 0;
|
||||
va->va_vaflags = 0;
|
||||
}
|
||||
|
||||
mode_t
|
||||
puffs_addvtype2mode(mode_t mode, enum vtype type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case VCHR:
|
||||
mode |= S_IFCHR;
|
||||
break;
|
||||
case VBLK:
|
||||
mode |= S_IFBLK;
|
||||
break;
|
||||
case VSOCK:
|
||||
mode |= S_IFSOCK;
|
||||
break;
|
||||
case VFIFO:
|
||||
mode |= S_IFIFO;
|
||||
break;
|
||||
case VREG:
|
||||
mode |= S_IFREG;
|
||||
break;
|
||||
case VLNK:
|
||||
mode |= S_IFLNK;
|
||||
break;
|
||||
case VDIR:
|
||||
mode |= S_IFDIR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/* $NetBSD: suspend.c,v 1.10 2009/12/05 12:13:08 pooka Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Antti Kantee. All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if !defined(lint)
|
||||
__RCSID("$NetBSD: suspend.c,v 1.10 2009/12/05 12:13:08 pooka Exp $");
|
||||
#endif /* !lint */
|
||||
|
||||
/*
|
||||
* File system suspension
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <puffs.h>
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
puffs_fs_suspend(struct puffs_usermount *pu)
|
||||
{
|
||||
|
||||
/* used to be, no longer is. just return error to avoid ABI bump */
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# $NetBSD: Makefile,v 1.9 2007/05/28 12:06:21 tls Exp $
|
||||
|
||||
USE_FORT?= yes # network protocol library
|
||||
|
||||
NOPIC= # defined
|
||||
NOPROFILE= # defined
|
||||
|
||||
LIB= rmt
|
||||
SRCS= rmtlib.c
|
||||
MAN= rmtops.3
|
||||
|
||||
.if defined(__MINIX)
|
||||
# rmtlib.c:451:50: error: format specifies type 'size_t' (aka 'unsigned long') \
|
||||
# but the argument has type 'size_t' (aka 'unsigned int') [-Werror,-Wformat]
|
||||
WARNS=0
|
||||
CFLAGS+=-Wno-format
|
||||
.endif
|
||||
|
||||
.if !defined(__MINIX)
|
||||
CPPFLAGS+= -D_REENTRANT
|
||||
.endif # !defined(__MINIX)
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# $NetBSD: README,v 1.2 1998/01/09 04:12:19 perry Exp $
|
||||
|
||||
README
|
||||
|
||||
This is the remote mag tape library. It allows a program that uses
|
||||
Unix system calls to transparently use a file (usually a tape drive) on
|
||||
another system via /etc/rmt, simply by including <rmt.h>. It is
|
||||
particularly useful with tar and dd, and is supplied with GNU tar.
|
||||
|
||||
This package has evolved somewhat over the years. My thanks to the
|
||||
people who did most of the original work, and those who've contributed
|
||||
bug fixes; appropriate credit is in the man page and source files.
|
||||
|
||||
Enjoy,
|
||||
|
||||
Arnold Robbins
|
||||
Emory U. Computing Center
|
||||
arnold@emoryu1.cc.emory.edu
|
||||
gatech!emoryu1!arnold
|
||||
+1 404 727 7636
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
/* $NetBSD: pathnames.h,v 1.2 2008/05/29 14:51:25 mrg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Matthew R. Green
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define _PATH_RSH "/usr/bin/rsh"
|
||||
#define _PATH_RMT "/etc/rmt"
|
||||
|
|
@ -1,896 +0,0 @@
|
|||
/* $NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $ */
|
||||
|
||||
/*
|
||||
* rmt --- remote tape emulator subroutines
|
||||
*
|
||||
* Originally written by Jeff Lee, modified some by Arnold Robbins
|
||||
*
|
||||
* WARNING: The man page rmt(8) for /etc/rmt documents the remote mag
|
||||
* tape protocol which rdump and rrestore use. Unfortunately, the man
|
||||
* page is *WRONG*. The author of the routines I'm including originally
|
||||
* wrote his code just based on the man page, and it didn't work, so he
|
||||
* went to the rdump source to figure out why. The only thing he had to
|
||||
* change was to check for the 'F' return code in addition to the 'E',
|
||||
* and to separate the various arguments with \n instead of a space. I
|
||||
* personally don't think that this is much of a problem, but I wanted to
|
||||
* point it out.
|
||||
* -- Arnold Robbins
|
||||
*
|
||||
* Redone as a library that can replace open, read, write, etc, by
|
||||
* Fred Fish, with some additional work by Arnold Robbins.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MAXUNIT --- Maximum number of remote tape file units
|
||||
*
|
||||
* READ --- Return the number of the read side file descriptor
|
||||
* WRITE --- Return the number of the write side file descriptor
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: rmtlib.c,v 1.26 2012/03/21 10:10:37 matt Exp $");
|
||||
|
||||
#define RMTIOCTL 1
|
||||
/* #define USE_REXEC 1 */ /* rexec code courtesy of Dan Kegel, srs!dan */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef RMTIOCTL
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mtio.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
|
||||
#ifdef USE_REXEC
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
#define __RMTLIB_PRIVATE
|
||||
#include <rmt.h> /* get prototypes for remapped functions */
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
static int _rmt_close(int);
|
||||
static int _rmt_ioctl(int, unsigned long, void *);
|
||||
static off_t _rmt_lseek(int, off_t, int);
|
||||
static int _rmt_open(const char *, int, int);
|
||||
static ssize_t _rmt_read(int, void *, size_t);
|
||||
static ssize_t _rmt_write(int, const void *, size_t);
|
||||
static int command(int, const char *);
|
||||
static int remdev(const char *);
|
||||
static void rmtabort(int);
|
||||
static int status(int);
|
||||
|
||||
|
||||
#define BUFMAGIC 64 /* a magic number for buffer sizes */
|
||||
#define MAXUNIT 4
|
||||
|
||||
#define READ(fd) (Ctp[fd][0])
|
||||
#define WRITE(fd) (Ptc[fd][1])
|
||||
|
||||
static int Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
|
||||
static int Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} };
|
||||
|
||||
|
||||
/*
|
||||
* rmtabort --- close off a remote tape connection
|
||||
*/
|
||||
static void
|
||||
rmtabort(int fildes)
|
||||
{
|
||||
|
||||
close(READ(fildes));
|
||||
close(WRITE(fildes));
|
||||
READ(fildes) = -1;
|
||||
WRITE(fildes) = -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* command --- attempt to perform a remote tape command
|
||||
*/
|
||||
static int
|
||||
command(int fildes, const char *buf)
|
||||
{
|
||||
size_t blen;
|
||||
sig_t pstat;
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
/*
|
||||
* save current pipe status and try to make the request
|
||||
*/
|
||||
|
||||
blen = strlen(buf);
|
||||
pstat = signal(SIGPIPE, SIG_IGN);
|
||||
if ((size_t)write(WRITE(fildes), buf, blen) == blen) {
|
||||
signal(SIGPIPE, pstat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* something went wrong. close down and go home
|
||||
*/
|
||||
|
||||
signal(SIGPIPE, pstat);
|
||||
rmtabort(fildes);
|
||||
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* status --- retrieve the status from the pipe
|
||||
*/
|
||||
static int
|
||||
status(int fildes)
|
||||
{
|
||||
int i;
|
||||
char c, *cp;
|
||||
char buffer[BUFMAGIC];
|
||||
|
||||
/*
|
||||
* read the reply command line
|
||||
*/
|
||||
|
||||
for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) {
|
||||
if (read(READ(fildes), cp, 1) != 1) {
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (*cp == '\n') {
|
||||
*cp = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == BUFMAGIC) {
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the return status
|
||||
*/
|
||||
|
||||
for (cp = buffer; *cp; cp++)
|
||||
if (*cp != ' ')
|
||||
break;
|
||||
|
||||
if (*cp == 'E' || *cp == 'F') {
|
||||
errno = atoi(cp + 1);
|
||||
while (read(READ(fildes), &c, 1) == 1)
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (*cp == 'F')
|
||||
rmtabort(fildes);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for mis-synced pipes
|
||||
*/
|
||||
|
||||
if (*cp != 'A') {
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return atoi(cp + 1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_REXEC
|
||||
/*
|
||||
* _rmt_rexec
|
||||
*
|
||||
* execute /etc/rmt on a remote system using rexec().
|
||||
* Return file descriptor of bidirectional socket for stdin and stdout
|
||||
* If username is NULL, or an empty string, uses current username.
|
||||
*
|
||||
* ADR: By default, this code is not used, since it requires that
|
||||
* the user have a .netrc file in his/her home directory, or that the
|
||||
* application designer be willing to have rexec prompt for login and
|
||||
* password info. This may be unacceptable, and .rhosts files for use
|
||||
* with rsh are much more common on BSD systems.
|
||||
*/
|
||||
|
||||
static int _rmt_rexec(const char *, const char *);
|
||||
|
||||
static int
|
||||
_rmt_rexec(const char *host, const char *user)
|
||||
{
|
||||
struct servent *rexecserv;
|
||||
|
||||
_DIAGASSERT(host != NULL);
|
||||
/* user may be NULL */
|
||||
|
||||
rexecserv = getservbyname("exec", "tcp");
|
||||
if (rexecserv == NULL)
|
||||
errx(1, "exec/tcp: service not available.");
|
||||
if ((user != NULL) && *user == '\0')
|
||||
user = NULL;
|
||||
return rexec(&host, rexecserv->s_port, user, NULL,
|
||||
"/etc/rmt", NULL);
|
||||
}
|
||||
#endif /* USE_REXEC */
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_open --- open a magtape device on system specified, as given user
|
||||
*
|
||||
* file name has the form [user@]system:/dev/????
|
||||
#ifdef COMPAT
|
||||
* file name has the form system[.user]:/dev/????
|
||||
#endif
|
||||
*/
|
||||
|
||||
#define MAXHOSTLEN 257 /* BSD allows very long host names... */
|
||||
|
||||
static int
|
||||
/*ARGSUSED*/
|
||||
_rmt_open(const char *path, int oflag, int mode)
|
||||
{
|
||||
int i;
|
||||
char buffer[BUFMAGIC];
|
||||
char host[MAXHOSTLEN];
|
||||
char device[BUFMAGIC];
|
||||
char login[BUFMAGIC];
|
||||
char *sys, *dev, *user;
|
||||
const char *rshpath, *rsh;
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
|
||||
sys = host;
|
||||
dev = device;
|
||||
user = login;
|
||||
|
||||
/*
|
||||
* first, find an open pair of file descriptors
|
||||
*/
|
||||
|
||||
for (i = 0; i < MAXUNIT; i++)
|
||||
if (READ(i) == -1 && WRITE(i) == -1)
|
||||
break;
|
||||
|
||||
if (i == MAXUNIT) {
|
||||
errno = EMFILE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* pull apart system and device, and optional user
|
||||
* don't munge original string
|
||||
* if COMPAT is defined, also handle old (4.2) style person.site notation.
|
||||
*/
|
||||
|
||||
while (*path != '@'
|
||||
#ifdef COMPAT
|
||||
&& *path != '.'
|
||||
#endif
|
||||
&& *path != ':') {
|
||||
*sys++ = *path++;
|
||||
}
|
||||
*sys = '\0';
|
||||
path++;
|
||||
|
||||
if (*(path - 1) == '@') {
|
||||
(void)strncpy(user, host, sizeof(login) - 1);
|
||||
/* saw user part of user@host */
|
||||
sys = host; /* start over */
|
||||
while (*path != ':') {
|
||||
*sys++ = *path++;
|
||||
}
|
||||
*sys = '\0';
|
||||
path++;
|
||||
}
|
||||
#ifdef COMPAT
|
||||
else if (*(path - 1) == '.') {
|
||||
while (*path != ':') {
|
||||
*user++ = *path++;
|
||||
}
|
||||
*user = '\0';
|
||||
path++;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
*user = '\0';
|
||||
|
||||
while (*path) {
|
||||
*dev++ = *path++;
|
||||
}
|
||||
*dev = '\0';
|
||||
|
||||
#ifdef USE_REXEC
|
||||
/*
|
||||
* Execute the remote command using rexec
|
||||
*/
|
||||
READ(i) = WRITE(i) = _rmt_rexec(host, login);
|
||||
if (READ(i) < 0)
|
||||
return -1;
|
||||
#else
|
||||
/*
|
||||
* setup the pipes for the 'rsh' command and fork
|
||||
*/
|
||||
|
||||
if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
|
||||
return -1;
|
||||
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
return -1;
|
||||
|
||||
case 0:
|
||||
close(0);
|
||||
dup(Ptc[i][0]);
|
||||
close(Ptc[i][0]); close(Ptc[i][1]);
|
||||
close(1);
|
||||
dup(Ctp[i][1]);
|
||||
close(Ctp[i][0]); close(Ctp[i][1]);
|
||||
(void) setuid(getuid());
|
||||
(void) setgid(getgid());
|
||||
|
||||
if ((rshpath = getenv("RCMD_CMD")) == NULL)
|
||||
rshpath = _PATH_RSH;
|
||||
if ((rsh = strrchr(rshpath, '/')) == NULL)
|
||||
rsh = rshpath;
|
||||
else
|
||||
rsh++;
|
||||
|
||||
if (*login) {
|
||||
execl(rshpath, rsh, host, "-l", login, _PATH_RMT, NULL);
|
||||
} else {
|
||||
execl(rshpath, rsh, host, _PATH_RMT, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* bad problems if we get here
|
||||
*/
|
||||
|
||||
err(1, "Cannnot exec %s", rshpath);
|
||||
/*FALLTHROUGH*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
close(Ptc[i][0]); close(Ctp[i][1]);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* now attempt to open the tape device
|
||||
*/
|
||||
|
||||
(void)snprintf(buffer, sizeof(buffer), "O%s\n%d\n", device, oflag);
|
||||
if (command(i, buffer) == -1 || status(i) == -1)
|
||||
return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_close --- close a remote magtape unit and shut down
|
||||
*/
|
||||
static int
|
||||
_rmt_close(int fildes)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (command(fildes, "C\n") != -1) {
|
||||
rc = status(fildes);
|
||||
|
||||
rmtabort(fildes);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_read --- read a buffer from a remote tape
|
||||
*/
|
||||
static ssize_t
|
||||
_rmt_read(int fildes, void *buf, size_t nbyte)
|
||||
{
|
||||
size_t rc;
|
||||
int rv;
|
||||
ssize_t nread;
|
||||
char *p;
|
||||
char buffer[BUFMAGIC];
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
(void)snprintf(buffer, sizeof buffer, "R%zu\n", nbyte);
|
||||
if (command(fildes, buffer) == -1 || (rv = status(fildes)) == -1)
|
||||
return -1;
|
||||
|
||||
if (rv > (int)nbyte)
|
||||
rv = (int)nbyte;
|
||||
|
||||
for (rc = rv, p = buf; rc > 0; rc -= nread, p += nread) {
|
||||
if ((nread = read(READ(fildes), p, rc)) <= 0) {
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_write --- write a buffer to the remote tape
|
||||
*/
|
||||
static ssize_t
|
||||
_rmt_write(int fildes, const void *buf, size_t nbyte)
|
||||
{
|
||||
char buffer[BUFMAGIC];
|
||||
sig_t pstat;
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
(void)snprintf(buffer, sizeof buffer, "W%zu\n", nbyte);
|
||||
if (command(fildes, buffer) == -1)
|
||||
return -1;
|
||||
|
||||
pstat = signal(SIGPIPE, SIG_IGN);
|
||||
if ((size_t)write(WRITE(fildes), buf, nbyte) == nbyte) {
|
||||
signal(SIGPIPE, pstat);
|
||||
return status(fildes);
|
||||
}
|
||||
|
||||
signal(SIGPIPE, pstat);
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_lseek --- perform an imitation lseek operation remotely
|
||||
*/
|
||||
static off_t
|
||||
_rmt_lseek(int fildes, off_t offset, int whence)
|
||||
{
|
||||
char buffer[BUFMAGIC];
|
||||
|
||||
/*LONGLONG*/
|
||||
(void)snprintf(buffer, sizeof buffer, "L%lld\n%d\n", (long long)offset,
|
||||
whence);
|
||||
if (command(fildes, buffer) == -1)
|
||||
return -1;
|
||||
|
||||
return status(fildes);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* _rmt_ioctl --- perform raw tape operations remotely
|
||||
*/
|
||||
#ifdef RMTIOCTL
|
||||
static int
|
||||
_rmt_ioctl(int fildes, unsigned long op, void *arg)
|
||||
{
|
||||
char c;
|
||||
int rv;
|
||||
size_t rc;
|
||||
ssize_t cnt;
|
||||
char buffer[BUFMAGIC], *p;
|
||||
struct mtop *mtop = arg;
|
||||
|
||||
_DIAGASSERT(arg != NULL);
|
||||
|
||||
/*
|
||||
* MTIOCOP is the easy one. nothing is transfered in binary
|
||||
*/
|
||||
|
||||
if (op == MTIOCTOP) {
|
||||
(void)snprintf(buffer, sizeof buffer, "I%d\n%d\n",
|
||||
mtop->mt_op, mtop->mt_count);
|
||||
if (command(fildes, buffer) == -1)
|
||||
return -1;
|
||||
return status(fildes);
|
||||
}
|
||||
|
||||
/*
|
||||
* we can only handle 2 ops, if not the other one, punt
|
||||
*/
|
||||
|
||||
if (op != MTIOCGET) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* grab the status and read it directly into the structure
|
||||
* this assumes that the status buffer is (hopefully) not
|
||||
* padded and that 2 shorts fit in a long without any word
|
||||
* alignment problems, ie - the whole struct is contiguous
|
||||
* NOTE - this is probably NOT a good assumption.
|
||||
*/
|
||||
|
||||
if (command(fildes, "S") == -1 || (rv = status(fildes)) == -1)
|
||||
return -1;
|
||||
|
||||
memset(arg, 0, sizeof(struct mtget));
|
||||
for (rc = rv, p = arg; rc > 0; rc -= cnt, p += cnt) {
|
||||
if ((cnt = read(READ(fildes), p, rc)) <= 0) {
|
||||
rmtabort(fildes);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* now we check for byte position. mt_type is a small integer field
|
||||
* (normally) so we will check its magnitude. if it is larger than
|
||||
* 256, we will assume that the bytes are swapped and go through
|
||||
* and reverse all the bytes
|
||||
*/
|
||||
|
||||
if (((struct mtget *)(void *)p)->mt_type < 256)
|
||||
return 0;
|
||||
|
||||
for (cnt = 0; cnt < rv; cnt += 2) {
|
||||
c = p[cnt];
|
||||
p[cnt] = p[cnt + 1];
|
||||
p[cnt + 1] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* RMTIOCTL */
|
||||
|
||||
|
||||
/*
|
||||
* Added routines to replace open(), close(), lseek(), ioctl(), etc.
|
||||
* The preprocessor can be used to remap these the rmtopen(), etc
|
||||
* thus minimizing source changes:
|
||||
*
|
||||
* #ifdef <something>
|
||||
* # define access rmtaccess
|
||||
* # define close rmtclose
|
||||
* # define creat rmtcreat
|
||||
* # define dup rmtdup
|
||||
* # define fcntl rmtfcntl
|
||||
* # define fstat rmtfstat
|
||||
* # define ioctl rmtioctl
|
||||
* # define isatty rmtisatty
|
||||
* # define lseek rmtlseek
|
||||
* # define lstat rmtlstat
|
||||
* # define open rmtopen
|
||||
* # define read rmtread
|
||||
* # define stat rmtstat
|
||||
* # define write rmtwrite
|
||||
* #endif
|
||||
*
|
||||
* -- Fred Fish
|
||||
*
|
||||
* ADR --- I set up a <rmt.h> include file for this
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note that local vs remote file descriptors are distinquished
|
||||
* by adding a bias to the remote descriptors. This is a quick
|
||||
* and dirty trick that may not be portable to some systems.
|
||||
*/
|
||||
|
||||
#define REM_BIAS 128
|
||||
|
||||
|
||||
/*
|
||||
* Test pathname to see if it is local or remote. A remote device
|
||||
* is any string that contains ":/dev/". Returns 1 if remote,
|
||||
* 0 otherwise.
|
||||
*/
|
||||
|
||||
static int
|
||||
remdev(const char *path)
|
||||
{
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
|
||||
if ((path = strchr(path, ':')) != NULL) {
|
||||
if (strncmp(path + 1, "/dev/", 5) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Open a local or remote file. Looks just like open(2) to
|
||||
* caller.
|
||||
*/
|
||||
int
|
||||
rmtopen(const char *path, int oflag, ...)
|
||||
{
|
||||
mode_t mode;
|
||||
int fd;
|
||||
va_list ap;
|
||||
va_start(ap, oflag);
|
||||
|
||||
mode = va_arg(ap, mode_t);
|
||||
va_end(ap);
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
|
||||
if (remdev(path)) {
|
||||
fd = _rmt_open(path, oflag, (int)mode);
|
||||
|
||||
return (fd == -1) ? -1 : (fd + REM_BIAS);
|
||||
} else {
|
||||
return open(path, oflag, mode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test pathname for specified access. Looks just like access(2)
|
||||
* to caller.
|
||||
*/
|
||||
|
||||
int
|
||||
rmtaccess(const char *path, int amode)
|
||||
{
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
|
||||
if (remdev(path)) {
|
||||
return 0; /* Let /etc/rmt find out */
|
||||
} else {
|
||||
return access(path, amode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Isrmt. Let a programmer know he has a remote device.
|
||||
*/
|
||||
int
|
||||
isrmt(int fd)
|
||||
{
|
||||
int unbias = fd - REM_BIAS;
|
||||
|
||||
return (fd >= REM_BIAS) && unbias < MAXUNIT &&
|
||||
(WRITE(unbias) != -1 || READ(unbias) != -1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read from stream. Looks just like read(2) to caller.
|
||||
*/
|
||||
ssize_t
|
||||
rmtread(int fildes, void *buf, size_t nbyte)
|
||||
{
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
return _rmt_read(fildes - REM_BIAS, buf, nbyte);
|
||||
} else {
|
||||
return read(fildes, buf, nbyte);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write to stream. Looks just like write(2) to caller.
|
||||
*/
|
||||
ssize_t
|
||||
rmtwrite(int fildes, const void *buf, size_t nbyte)
|
||||
{
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
return _rmt_write(fildes - REM_BIAS, buf, nbyte);
|
||||
} else {
|
||||
return write(fildes, buf, nbyte);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform lseek on file. Looks just like lseek(2) to caller.
|
||||
*/
|
||||
off_t
|
||||
rmtlseek(int fildes, off_t offset, int whence)
|
||||
{
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
return _rmt_lseek(fildes - REM_BIAS, offset, whence);
|
||||
} else {
|
||||
return lseek(fildes, offset, whence);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close a file. Looks just like close(2) to caller.
|
||||
*/
|
||||
int
|
||||
rmtclose(int fildes)
|
||||
{
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
return _rmt_close(fildes - REM_BIAS);
|
||||
} else {
|
||||
return close(fildes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do ioctl on file. Looks just like ioctl(2) to caller.
|
||||
*/
|
||||
int
|
||||
rmtioctl(int fildes, unsigned long request, ...)
|
||||
{
|
||||
void *arg;
|
||||
va_list ap;
|
||||
va_start(ap, request);
|
||||
|
||||
arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
/* XXX: arg may be NULL ? */
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
#ifdef RMTIOCTL
|
||||
return _rmt_ioctl(fildes - REM_BIAS, request, arg);
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
return -1; /* For now (fnf) */
|
||||
#endif
|
||||
} else {
|
||||
return ioctl(fildes, request, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Duplicate an open file descriptor. Looks just like dup(2)
|
||||
* to caller.
|
||||
*/
|
||||
int
|
||||
rmtdup(int fildes)
|
||||
{
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1; /* For now (fnf) */
|
||||
} else {
|
||||
return dup(fildes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get file status. Looks just like fstat(2) to caller.
|
||||
*/
|
||||
int
|
||||
rmtfstat(int fildes, struct stat *buf)
|
||||
{
|
||||
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
if (isrmt(fildes)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1; /* For now (fnf) */
|
||||
} else {
|
||||
return fstat(fildes, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get file status. Looks just like stat(2) to caller.
|
||||
*/
|
||||
int
|
||||
rmtstat(const char *path, struct stat *buf)
|
||||
{
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
if (remdev(path)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1; /* For now (fnf) */
|
||||
} else {
|
||||
return stat(path, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a file from scratch. Looks just like creat(2) to the caller.
|
||||
*/
|
||||
int
|
||||
rmtcreat(const char *path, mode_t mode)
|
||||
{
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
|
||||
if (remdev(path)) {
|
||||
return rmtopen(path, O_WRONLY | O_CREAT, mode);
|
||||
} else {
|
||||
return open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rmtfcntl. Do a remote fcntl operation.
|
||||
*/
|
||||
int
|
||||
rmtfcntl(int fd, int cmd, ...)
|
||||
{
|
||||
void *arg;
|
||||
va_list ap;
|
||||
va_start(ap, cmd);
|
||||
|
||||
arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
/* XXX: arg may be NULL ? */
|
||||
|
||||
if (isrmt(fd)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
} else {
|
||||
return fcntl(fd, cmd, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rmtisatty. Do the isatty function.
|
||||
*/
|
||||
int
|
||||
rmtisatty(int fd)
|
||||
{
|
||||
|
||||
if (isrmt(fd))
|
||||
return 0;
|
||||
else
|
||||
return isatty(fd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get file status, even if symlink. Looks just like lstat(2) to caller.
|
||||
*/
|
||||
int
|
||||
rmtlstat(const char *path, struct stat *buf)
|
||||
{
|
||||
|
||||
_DIAGASSERT(path != NULL);
|
||||
_DIAGASSERT(buf != NULL);
|
||||
|
||||
if (remdev(path)) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1; /* For now (fnf) */
|
||||
} else {
|
||||
return lstat(path, buf);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
.\" $NetBSD: rmtops.3,v 1.14 2010/03/22 22:00:37 joerg Exp $
|
||||
.\"
|
||||
.Dd October 16, 2001
|
||||
.Dt RMTOPS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm rmtops
|
||||
.Nd access tape drives on remote machines
|
||||
.Sh LIBRARY
|
||||
Remote Magnetic Tape Library (librmt, -lrmt)
|
||||
.Sh SYNOPSIS
|
||||
.In rmt.h
|
||||
.In sys/stat.h
|
||||
.Ft int
|
||||
.Fn isrmt "int fd"
|
||||
.Ft int
|
||||
.Fn rmtaccess "char *file" "int mode"
|
||||
.Ft int
|
||||
.Fn rmtclose "int fd"
|
||||
.Ft int
|
||||
.Fn rmtcreat "char *file" "int mode"
|
||||
.Ft int
|
||||
.Fn rmtdup "int fd"
|
||||
.Ft int
|
||||
.Fn rmtfcntl "int fd" "int cmd" "int arg"
|
||||
.Ft int
|
||||
.Fn rmtfstat "int fd" "struct stat *buf"
|
||||
.Ft int
|
||||
.Fn rmtioctl "int fd" "int request" "char *argp"
|
||||
.Ft int
|
||||
.Fn rmtisatty "int fd"
|
||||
.Ft long
|
||||
.Fn rmtlseek "int fd" "long offset" "int whence"
|
||||
.Ft int
|
||||
.Fn rmtlstat "char *file" "struct stat *buf"
|
||||
.Ft int
|
||||
.Fn rmtopen "char *file" "int flags" "int mode"
|
||||
.Ft int
|
||||
.Fn rmtread "int fd" "char *buf" "int nbytes"
|
||||
.Ft int
|
||||
.Fn rmtstat "char *file" "struct stat *buf"
|
||||
.Ft int
|
||||
.Fn rmtwrite "int fd" "char *buf" "int nbytes"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
library provides a simple means of transparently accessing tape drives
|
||||
on remote machines via
|
||||
.Xr rsh 1
|
||||
and
|
||||
.Xr rmt 8 .
|
||||
These routines are used like their corresponding system calls, but
|
||||
allow the user to open up a tape drive on a remote system on which he
|
||||
or she has an account and the appropriate remote permissions.
|
||||
.Pp
|
||||
A remote tape drive file name has the form
|
||||
.Dl [user@]hostname:/dev/???
|
||||
where
|
||||
.Em system
|
||||
is the remote system,
|
||||
.Em /dev/???
|
||||
is the particular drive on the remote system (raw, blocked, rewinding,
|
||||
non-rewinding, etc.), and the optional
|
||||
.Em user
|
||||
is the login name to be used on the remote system, if different from
|
||||
the current user's login name.
|
||||
.\" .Pp
|
||||
.\" The library source code may be optionally compiled to recognize the
|
||||
.\" old
|
||||
.\" .Bx 4.2 ,
|
||||
.\" remote syntax
|
||||
.\" .sp
|
||||
.\" hostname[.user]:/dev/???
|
||||
.\" .sp
|
||||
.\" By default, only the first form (introduced in
|
||||
.\" .Bx 4.3 )
|
||||
.\" is recognized.
|
||||
.Pp
|
||||
For transparency, the user should include the file
|
||||
.In rmt.h ,
|
||||
which has the following defines in it:
|
||||
.Bd -literal
|
||||
#define access rmtaccess
|
||||
#define close rmtclose
|
||||
#define creat rmtcreat
|
||||
#define dup rmtdup
|
||||
#define fcntl rmtfcntl
|
||||
#define fstat rmtfstat
|
||||
#define ioctl rmtioctl
|
||||
#define isatty rmtisatty
|
||||
#define lseek rmtlseek
|
||||
#define lstat rmtlstat
|
||||
#define open rmtopen
|
||||
#define read rmtread
|
||||
#define stat rmtstat
|
||||
#define write rmtwrite
|
||||
.Ed
|
||||
.Pp
|
||||
This allows the programmer to use
|
||||
.Xr open 2 ,
|
||||
.Xr close 2 ,
|
||||
.Xr read 2 ,
|
||||
.Xr write 2 ,
|
||||
etc. in their normal fashion, with the
|
||||
.Nm
|
||||
routines taking care of differentiating between local and remote files.
|
||||
This file should be included
|
||||
.Em before
|
||||
including the file
|
||||
.Pa \*[Lt]sys/stat.h\*[Gt] ,
|
||||
since it redefines the identifier ``stat'' which is used to declare
|
||||
objects of type
|
||||
.Em "struct stat" .
|
||||
.Pp
|
||||
The routines differentiate between local and remote file descriptors
|
||||
by adding a bias (currently 128) to the file descriptor of the pipe.
|
||||
The programmer, if he or she must know if a file is remote, should use
|
||||
.Fn isrmt .
|
||||
.Sh ENVIRONMENT
|
||||
The RCMD_CMD environment variable can be set to the name or pathname
|
||||
of a program to use, instead of
|
||||
.Pa /usr/bin/rsh ,
|
||||
and must have the same calling conventions as
|
||||
.Xr rsh 1 .
|
||||
.Sh FILES
|
||||
.Bl -tag -width /usr/lib/librmt.a -compact
|
||||
.It Pa /usr/lib/librmt.a
|
||||
remote tape library
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
Several of these routines will return \-1 and set
|
||||
.Va errno
|
||||
to EOPNOTSUPP, if they are given a remote file name or a file descriptor
|
||||
on an open remote file (e.g.,
|
||||
.Fn rmtdup ) .
|
||||
.Sh SEE ALSO
|
||||
.Xr rcp 1 ,
|
||||
.Xr rsh 1 ,
|
||||
.Xr rmt 8
|
||||
.Pp
|
||||
And the appropriate system calls in section 2.
|
||||
.\" .Sh CONFIGURATION OPTIONS
|
||||
.\" The library may be compiled to allow the use of
|
||||
.\" .Bx 4.2 -style
|
||||
.\" remote file names. This is not recommended.
|
||||
.\" .Pp
|
||||
.\" By default, the library opens two pipes to
|
||||
.\" .Xr rsh 1 .
|
||||
.\" It may optionally be compiled to use
|
||||
.\" .Xr rexec 3 ,
|
||||
.\" instead. Doing so requires the use of a
|
||||
.\" .Em .netrc
|
||||
.\" file in the user's home directory, or that the application designer be
|
||||
.\" willing to have
|
||||
.\" .Xr rexec 3
|
||||
.\" prompt the user for a login name and password on the remote host.
|
||||
.Sh AUTHORS
|
||||
Jeff Lee wrote the original routines for accessing tape drives via
|
||||
.Xr rmt 8 .
|
||||
.Pp
|
||||
Fred Fish redid them into a general purpose library.
|
||||
.Pp
|
||||
Arnold Robbins added the ability to specify a user name on the remote
|
||||
system, the
|
||||
.Pa \*[Lt]rmt.h\*[Gt]
|
||||
include file, this man page, cleaned up the library a little, and made
|
||||
the appropriate changes for
|
||||
.Bx 4.3 .
|
||||
.Pp
|
||||
Dan Kegel contributed the code to use the
|
||||
.Xr rexec 3
|
||||
library routine.
|
||||
.Sh BUGS
|
||||
There is no way to use remote tape drives with
|
||||
.Xr stdio 3 ,
|
||||
short of recompiling it entirely to use these routines.
|
||||
.Pp
|
||||
The
|
||||
.Xr rmt 8
|
||||
protocol is not very capable.
|
||||
In particular, it relies on TCP/IP sockets for error
|
||||
free transmission, and does no data validation of its own.
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# from: @(#)Makefile 8.2 (Berkeley) 12/15/93
|
||||
# $NetBSD: Makefile,v 1.36 2012/08/10 12:20:10 joerg Exp $
|
||||
|
||||
USE_FORT?= yes # network protocol library
|
||||
|
||||
LIBISPRIVATE= yes
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
LIB= telnet
|
||||
SRCS= auth.c encrypt.c genget.c getent.c misc.c
|
||||
|
||||
CPPFLAGS+= -DHAS_CGETENT
|
||||
CPPFLAGS+= -I${.CURDIR}
|
||||
|
||||
.if ${MKCRYPTO} != "no"
|
||||
SRCS+= enc_des.c
|
||||
CPPFLAGS+= -DENCRYPTION -DAUTHENTICATION
|
||||
CPPFLAGS+= -DDES_ENCRYPTION
|
||||
.endif
|
||||
|
||||
.if ${USE_KERBEROS} != "no"
|
||||
SRCS+= kerberos5.c
|
||||
CPPFLAGS+= -DKRB5
|
||||
.endif
|
||||
|
||||
.if ${USE_PAM} != "no" && ${MKCRYPTO} != "no"
|
||||
SRCS+= sra.c pk.c
|
||||
CPPFLAGS+= -DSRA
|
||||
.endif
|
||||
|
||||
.for f in auth enc_des kerberos5 pk
|
||||
COPTS.${f}.c+= -Wno-pointer-sign
|
||||
.endfor
|
||||
|
||||
.include <bsd.lib.mk>
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
/* $NetBSD: auth-proto.h,v 1.15 2006/03/20 21:23:47 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)auth-proto.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef _LIBTELNET_AUTH_PROTO_H_
|
||||
#define _LIBTELNET_AUTH_PROTO_H_
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifdef AUTHENTICATION
|
||||
Authenticator *findauthenticator(int, int);
|
||||
|
||||
void auth_init(const char *, int);
|
||||
int auth_cmd(int, char **);
|
||||
void auth_request(void);
|
||||
void auth_send(unsigned char *, int);
|
||||
void auth_send_retry(void);
|
||||
void auth_is(unsigned char *, int);
|
||||
void auth_reply(unsigned char *, int);
|
||||
void auth_disable_name(char *);
|
||||
void auth_gen_printsub(unsigned char *, int, unsigned char *, int);
|
||||
|
||||
int getauthmask(char *, int *);
|
||||
int auth_enable(char *);
|
||||
int auth_disable(char *);
|
||||
int auth_onoff(char *, int);
|
||||
int auth_togdebug(int);
|
||||
int auth_status(char *);
|
||||
void auth_name(unsigned char *, int);
|
||||
int auth_sendname(unsigned char *, int);
|
||||
void auth_finished(Authenticator *, int);
|
||||
int auth_wait(char *, size_t);
|
||||
void auth_debug(int);
|
||||
void auth_printsub(unsigned char *, int, unsigned char *, int);
|
||||
|
||||
#ifdef KRB5
|
||||
int kerberos5_init(Authenticator *, int);
|
||||
int kerberos5_send(Authenticator *);
|
||||
void kerberos5_is(Authenticator *, unsigned char *, int);
|
||||
void kerberos5_reply(Authenticator *, unsigned char *, int);
|
||||
int kerberos5_status(Authenticator *, char *, size_t, int);
|
||||
void kerberos5_printsub(unsigned char *, int, unsigned char *, int);
|
||||
#endif
|
||||
|
||||
#ifdef SRA
|
||||
int sra_init(Authenticator *, int);
|
||||
int sra_send(Authenticator *);
|
||||
void sra_is(Authenticator *, unsigned char *, int);
|
||||
void sra_reply(Authenticator *, unsigned char *, int);
|
||||
int sra_status(Authenticator *, char *, size_t, int);
|
||||
void sra_printsub(unsigned char *, int, unsigned char *, int);
|
||||
#endif
|
||||
|
||||
#endif /* AUTHENTICATION */
|
||||
#endif /* _LIBTELNET_AUTH_PROTO_H_ */
|
||||
|
|
@ -1,617 +0,0 @@
|
|||
/* $NetBSD: auth.c,v 1.21 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)auth.c 8.3 (Berkeley) 5/30/95"
|
||||
#else
|
||||
__RCSID("$NetBSD: auth.c,v 1.21 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef AUTHENTICATION
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#define AUTH_NAMES
|
||||
#include <arpa/telnet.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#ifdef NO_STRING_H
|
||||
#include <strings.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "encrypt.h"
|
||||
#include "auth.h"
|
||||
#include "misc-proto.h"
|
||||
#include "auth-proto.h"
|
||||
|
||||
#define typemask(x) (1<<((x)-1))
|
||||
|
||||
#ifdef RSA_ENCPWD
|
||||
extern rsaencpwd_init();
|
||||
extern rsaencpwd_send();
|
||||
extern rsaencpwd_is();
|
||||
extern rsaencpwd_reply();
|
||||
extern rsaencpwd_status();
|
||||
extern rsaencpwd_printsub();
|
||||
#endif
|
||||
|
||||
int auth_debug_mode = 0;
|
||||
static const char *Name = "Noname";
|
||||
static int Server = 0;
|
||||
static Authenticator *authenticated = 0;
|
||||
static int authenticating = 0;
|
||||
static int validuser = 0;
|
||||
static unsigned char _auth_send_data[256];
|
||||
static unsigned char *auth_send_data;
|
||||
static int auth_send_cnt = 0;
|
||||
|
||||
static void auth_intr(int);
|
||||
|
||||
/*
|
||||
* Authentication types supported. Plese note that these are stored
|
||||
* in priority order, i.e. try the first one first.
|
||||
*/
|
||||
Authenticator authenticators[] = {
|
||||
#ifdef SPX
|
||||
{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
|
||||
spx_init,
|
||||
spx_send,
|
||||
spx_is,
|
||||
spx_reply,
|
||||
spx_status,
|
||||
spx_printsub },
|
||||
{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
|
||||
spx_init,
|
||||
spx_send,
|
||||
spx_is,
|
||||
spx_reply,
|
||||
spx_status,
|
||||
spx_printsub },
|
||||
#endif
|
||||
#ifdef KRB5
|
||||
# ifdef ENCRYPTION
|
||||
{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
|
||||
kerberos5_init,
|
||||
kerberos5_send,
|
||||
kerberos5_is,
|
||||
kerberos5_reply,
|
||||
kerberos5_status,
|
||||
kerberos5_printsub },
|
||||
# endif /* ENCRYPTION */
|
||||
{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
|
||||
kerberos5_init,
|
||||
kerberos5_send,
|
||||
kerberos5_is,
|
||||
kerberos5_reply,
|
||||
kerberos5_status,
|
||||
kerberos5_printsub },
|
||||
#endif
|
||||
#ifdef RSA_ENCPWD
|
||||
{ AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
|
||||
rsaencpwd_init,
|
||||
rsaencpwd_send,
|
||||
rsaencpwd_is,
|
||||
rsaencpwd_reply,
|
||||
rsaencpwd_status,
|
||||
rsaencpwd_printsub },
|
||||
#endif
|
||||
#ifdef SRA
|
||||
{ AUTHTYPE_SRA, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
|
||||
sra_init,
|
||||
sra_send,
|
||||
sra_is,
|
||||
sra_reply,
|
||||
sra_status,
|
||||
sra_printsub },
|
||||
|
||||
#endif
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
static Authenticator NoAuth = { .type = 0 };
|
||||
|
||||
static int i_support = 0;
|
||||
static int i_wont_support = 0;
|
||||
|
||||
Authenticator *
|
||||
findauthenticator(int type, int way)
|
||||
{
|
||||
Authenticator *ap = authenticators;
|
||||
|
||||
while (ap->type && (ap->type != type || ap->way != way))
|
||||
++ap;
|
||||
return(ap->type ? ap : 0);
|
||||
}
|
||||
|
||||
void
|
||||
auth_init(const char *name, int server)
|
||||
{
|
||||
Authenticator *ap = authenticators;
|
||||
|
||||
Server = server;
|
||||
Name = name;
|
||||
|
||||
i_support = 0;
|
||||
authenticated = 0;
|
||||
authenticating = 0;
|
||||
while (ap->type) {
|
||||
if (!ap->init || (*ap->init)(ap, server)) {
|
||||
i_support |= typemask(ap->type);
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: I support auth type %d %d\r\n",
|
||||
Name,
|
||||
ap->type, ap->way);
|
||||
}
|
||||
else if (auth_debug_mode)
|
||||
printf(">>>%s: Init failed: auth type %d %d\r\n",
|
||||
Name, ap->type, ap->way);
|
||||
++ap;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
auth_disable_name(char *name)
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < AUTHTYPE_CNT; ++x) {
|
||||
if (AUTHTYPE_NAME(x) && !strcasecmp(name, AUTHTYPE_NAME(x))) {
|
||||
i_wont_support |= typemask(x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getauthmask(char *type, int *maskp)
|
||||
{
|
||||
register int x;
|
||||
|
||||
if (AUTHTYPE_NAME(0) && !strcasecmp(type, AUTHTYPE_NAME(0))) {
|
||||
*maskp = -1;
|
||||
return(1);
|
||||
}
|
||||
|
||||
for (x = 1; x < AUTHTYPE_CNT; ++x) {
|
||||
if (AUTHTYPE_NAME(x) && !strcasecmp(type, AUTHTYPE_NAME(x))) {
|
||||
*maskp = typemask(x);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
auth_enable(char *type)
|
||||
{
|
||||
return(auth_onoff(type, 1));
|
||||
}
|
||||
|
||||
int
|
||||
auth_disable(char *type)
|
||||
{
|
||||
return(auth_onoff(type, 0));
|
||||
}
|
||||
|
||||
int
|
||||
auth_onoff(char *type, int on)
|
||||
{
|
||||
int i, mask = -1;
|
||||
Authenticator *ap;
|
||||
|
||||
if (!strcasecmp(type, "?") || !strcasecmp(type, "help")) {
|
||||
printf("auth %s 'type'\n", on ? "enable" : "disable");
|
||||
printf("Where 'type' is one of:\n");
|
||||
printf("\t%s\n", AUTHTYPE_NAME(0));
|
||||
mask = 0;
|
||||
for (ap = authenticators; ap->type; ap++) {
|
||||
if ((mask & (i = typemask(ap->type))) != 0)
|
||||
continue;
|
||||
mask |= i;
|
||||
printf("\t%s\n", AUTHTYPE_NAME(ap->type));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!getauthmask(type, &mask)) {
|
||||
printf("%s: invalid authentication type\n", type);
|
||||
return(0);
|
||||
}
|
||||
if (on)
|
||||
i_wont_support &= ~mask;
|
||||
else
|
||||
i_wont_support |= mask;
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
auth_togdebug(int on)
|
||||
{
|
||||
if (on < 0)
|
||||
auth_debug_mode ^= 1;
|
||||
else
|
||||
auth_debug_mode = on;
|
||||
printf("auth debugging %s\n", auth_debug_mode ? "enabled" : "disabled");
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
auth_status(char *s)
|
||||
{
|
||||
Authenticator *ap;
|
||||
int i, mask;
|
||||
|
||||
if (i_wont_support == -1)
|
||||
printf("Authentication disabled\n");
|
||||
else
|
||||
printf("Authentication enabled\n");
|
||||
|
||||
mask = 0;
|
||||
for (ap = authenticators; ap->type; ap++) {
|
||||
if ((mask & (i = typemask(ap->type))) != 0)
|
||||
continue;
|
||||
mask |= i;
|
||||
printf("%s: %s\n", AUTHTYPE_NAME(ap->type),
|
||||
(i_wont_support & typemask(ap->type)) ?
|
||||
"disabled" : "enabled");
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is called by the server to start authentication
|
||||
* negotiation.
|
||||
*/
|
||||
void
|
||||
auth_request(void)
|
||||
{
|
||||
static unsigned char str_request[64] = { IAC, SB,
|
||||
TELOPT_AUTHENTICATION,
|
||||
TELQUAL_SEND, };
|
||||
Authenticator *ap = authenticators;
|
||||
unsigned char *e = str_request + 4;
|
||||
|
||||
if (!authenticating) {
|
||||
authenticating = 1;
|
||||
while (ap->type) {
|
||||
if (i_support & ~i_wont_support & typemask(ap->type)) {
|
||||
if (auth_debug_mode) {
|
||||
printf(">>>%s: Sending type %d %d\r\n",
|
||||
Name, ap->type, ap->way);
|
||||
}
|
||||
*e++ = ap->type;
|
||||
*e++ = ap->way;
|
||||
}
|
||||
++ap;
|
||||
}
|
||||
*e++ = IAC;
|
||||
*e++ = SE;
|
||||
telnet_net_write(str_request, e - str_request);
|
||||
printsub('>', &str_request[2], e - str_request - 2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when an AUTH SEND is received.
|
||||
* It should never arrive on the server side (as only the server can
|
||||
* send an AUTH SEND).
|
||||
* You should probably respond to it if you can...
|
||||
*
|
||||
* If you want to respond to the types out of order (i.e. even
|
||||
* if he sends LOGIN KERBEROS and you support both, you respond
|
||||
* with KERBEROS instead of LOGIN (which is against what the
|
||||
* protocol says)) you will have to hack this code...
|
||||
*/
|
||||
void
|
||||
auth_send(unsigned char *data, int cnt)
|
||||
{
|
||||
Authenticator *ap;
|
||||
static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION,
|
||||
TELQUAL_IS, AUTHTYPE_NULL, 0,
|
||||
IAC, SE };
|
||||
if (Server) {
|
||||
if (auth_debug_mode) {
|
||||
printf(">>>%s: auth_send called!\r\n", Name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (auth_debug_mode) {
|
||||
printf(">>>%s: auth_send got:", Name);
|
||||
printd(data, cnt); printf("\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the data, if it is new, so that we can continue looking
|
||||
* at it if the authorization we try doesn't work
|
||||
*/
|
||||
if (data < _auth_send_data ||
|
||||
data > _auth_send_data + sizeof(_auth_send_data)) {
|
||||
auth_send_cnt = (size_t)cnt > sizeof(_auth_send_data)
|
||||
? sizeof(_auth_send_data)
|
||||
: (size_t)cnt;
|
||||
memmove(_auth_send_data, data, auth_send_cnt);
|
||||
auth_send_data = _auth_send_data;
|
||||
} else {
|
||||
/*
|
||||
* This is probably a no-op, but we just make sure
|
||||
*/
|
||||
auth_send_data = data;
|
||||
auth_send_cnt = cnt;
|
||||
}
|
||||
while ((auth_send_cnt -= 2) >= 0) {
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: He supports %d\r\n",
|
||||
Name, *auth_send_data);
|
||||
if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) {
|
||||
ap = findauthenticator(auth_send_data[0],
|
||||
auth_send_data[1]);
|
||||
if (ap && ap->send) {
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Trying %d %d\r\n",
|
||||
Name, auth_send_data[0],
|
||||
auth_send_data[1]);
|
||||
if ((*ap->send)(ap)) {
|
||||
/*
|
||||
* Okay, we found one we like
|
||||
* and did it.
|
||||
* we can go home now.
|
||||
*/
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Using type %d\r\n",
|
||||
Name, *auth_send_data);
|
||||
auth_send_data += 2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* else
|
||||
* just continue on and look for the
|
||||
* next one if we didn't do anything.
|
||||
*/
|
||||
}
|
||||
auth_send_data += 2;
|
||||
}
|
||||
telnet_net_write(str_none, sizeof(str_none));
|
||||
printsub('>', &str_none[2], sizeof(str_none) - 2);
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Sent failure message\r\n", Name);
|
||||
auth_finished(0, AUTH_REJECT);
|
||||
#ifdef KANNAN
|
||||
/*
|
||||
* We requested strong authentication, however no mechanisms worked.
|
||||
* Therefore, exit on client end.
|
||||
*/
|
||||
printf("Unable to securely authenticate user ... exit\n");
|
||||
exit(0);
|
||||
#endif /* KANNAN */
|
||||
}
|
||||
|
||||
void
|
||||
auth_send_retry(void)
|
||||
{
|
||||
/*
|
||||
* if auth_send_cnt <= 0 then auth_send will end up rejecting
|
||||
* the authentication and informing the other side of this.
|
||||
*/
|
||||
auth_send(auth_send_data, auth_send_cnt);
|
||||
}
|
||||
|
||||
void
|
||||
auth_is(unsigned char *data, int cnt)
|
||||
{
|
||||
Authenticator *ap;
|
||||
|
||||
if (cnt < 2)
|
||||
return;
|
||||
|
||||
if (data[0] == AUTHTYPE_NULL) {
|
||||
auth_finished(0, AUTH_REJECT);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ap = findauthenticator(data[0], data[1])) != NULL) {
|
||||
if (ap->is)
|
||||
(*ap->is)(ap, data+2, cnt-2);
|
||||
} else if (auth_debug_mode)
|
||||
printf(">>>%s: Invalid authentication in IS: %d\r\n",
|
||||
Name, *data);
|
||||
}
|
||||
|
||||
void
|
||||
auth_reply(unsigned char *data, int cnt)
|
||||
{
|
||||
Authenticator *ap;
|
||||
|
||||
if (cnt < 2)
|
||||
return;
|
||||
|
||||
if ((ap = findauthenticator(data[0], data[1])) != NULL) {
|
||||
if (ap->reply)
|
||||
(*ap->reply)(ap, data+2, cnt-2);
|
||||
} else if (auth_debug_mode)
|
||||
printf(">>>%s: Invalid authentication in SEND: %d\r\n",
|
||||
Name, *data);
|
||||
}
|
||||
|
||||
void
|
||||
auth_name(unsigned char *data, int cnt)
|
||||
{
|
||||
unsigned char savename[256];
|
||||
|
||||
if (cnt < 1) {
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Empty name in NAME\r\n", Name);
|
||||
return;
|
||||
}
|
||||
if ((size_t)cnt > sizeof(savename) - 1) {
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Name in NAME (%d) exceeds %ld length\r\n",
|
||||
Name, cnt, (long)sizeof(savename)-1);
|
||||
return;
|
||||
}
|
||||
memmove((void *)savename, (void *)data, cnt);
|
||||
savename[cnt] = '\0'; /* Null terminate */
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: Got NAME [%s]\r\n", Name, savename);
|
||||
auth_encrypt_user(savename);
|
||||
}
|
||||
|
||||
int
|
||||
auth_sendname(unsigned char *cp, int len)
|
||||
{
|
||||
static unsigned char str_request[256+6]
|
||||
= { IAC, SB, TELOPT_AUTHENTICATION, TELQUAL_NAME, };
|
||||
register unsigned char *e = str_request + 4;
|
||||
register unsigned char *ee = &str_request[sizeof(str_request)-2];
|
||||
|
||||
while (--len >= 0) {
|
||||
if ((*e++ = *cp++) == IAC)
|
||||
*e++ = IAC;
|
||||
if (e >= ee)
|
||||
return(0);
|
||||
}
|
||||
*e++ = IAC;
|
||||
*e++ = SE;
|
||||
telnet_net_write(str_request, e - str_request);
|
||||
printsub('>', &str_request[2], e - &str_request[2]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
auth_finished(Authenticator *ap, int result)
|
||||
{
|
||||
if (!(authenticated = ap))
|
||||
authenticated = &NoAuth;
|
||||
validuser = result;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
auth_intr(int sig)
|
||||
{
|
||||
auth_finished(0, AUTH_REJECT);
|
||||
}
|
||||
|
||||
int
|
||||
auth_wait(char *name, size_t l)
|
||||
{
|
||||
if (auth_debug_mode)
|
||||
printf(">>>%s: in auth_wait.\r\n", Name);
|
||||
|
||||
if (Server && !authenticating)
|
||||
return(0);
|
||||
|
||||
(void) signal(SIGALRM, auth_intr);
|
||||
alarm(30);
|
||||
while (!authenticated)
|
||||
if (telnet_spin())
|
||||
break;
|
||||
alarm(0);
|
||||
(void) signal(SIGALRM, SIG_DFL);
|
||||
|
||||
/*
|
||||
* Now check to see if the user is valid or not
|
||||
*/
|
||||
if (!authenticated || authenticated == &NoAuth)
|
||||
return(AUTH_REJECT);
|
||||
|
||||
if (validuser == AUTH_VALID)
|
||||
validuser = AUTH_USER;
|
||||
|
||||
if (authenticated->status)
|
||||
validuser = (*authenticated->status)(authenticated,
|
||||
name, l, validuser);
|
||||
return(validuser);
|
||||
}
|
||||
|
||||
void
|
||||
auth_debug(int mode)
|
||||
{
|
||||
auth_debug_mode = mode;
|
||||
}
|
||||
|
||||
void
|
||||
auth_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
|
||||
{
|
||||
Authenticator *ap;
|
||||
|
||||
if ((ap = findauthenticator(data[1], data[2])) && ap->printsub)
|
||||
(*ap->printsub)(data, cnt, buf, buflen);
|
||||
else
|
||||
auth_gen_printsub(data, cnt, buf, buflen);
|
||||
}
|
||||
|
||||
void
|
||||
auth_gen_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
|
||||
{
|
||||
register unsigned char *cp;
|
||||
unsigned char tbuf[16];
|
||||
|
||||
cnt -= 3;
|
||||
data += 3;
|
||||
buf[buflen-1] = '\0';
|
||||
buf[buflen-2] = '*';
|
||||
buflen -= 2;
|
||||
for (; cnt > 0; cnt--, data++) {
|
||||
snprintf((char *)tbuf, sizeof(tbuf), " %d", *data);
|
||||
for (cp = tbuf; *cp && buflen > 0; --buflen)
|
||||
*buf++ = *cp++;
|
||||
if (buflen <= 0)
|
||||
return;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/* $NetBSD: auth.h,v 1.11 2005/02/06 05:53:07 perry Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)auth.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef __AUTH__
|
||||
#define __AUTH__
|
||||
|
||||
#define AUTH_REJECT 0 /* Rejected */
|
||||
#define AUTH_UNKNOWN 1 /* We don't know who he is, but he's okay */
|
||||
#define AUTH_OTHER 2 /* We know him, but not his name */
|
||||
#define AUTH_USER 3 /* We know he name */
|
||||
#define AUTH_VALID 4 /* We know him, and he needs no password */
|
||||
|
||||
typedef struct XauthP {
|
||||
int type;
|
||||
int way;
|
||||
int (*init)(struct XauthP *, int);
|
||||
int (*send)(struct XauthP *);
|
||||
void (*is)(struct XauthP *, unsigned char *, int);
|
||||
void (*reply)(struct XauthP *, unsigned char *, int);
|
||||
int (*status)(struct XauthP *, char *, size_t, int);
|
||||
void (*printsub)(unsigned char *, int, unsigned char *, int);
|
||||
} Authenticator;
|
||||
|
||||
#include "auth-proto.h"
|
||||
|
||||
#define OPTS_FORWARD_CREDS 0x00000002
|
||||
#define OPTS_FORWARDABLE_CREDS 0x00000001
|
||||
|
||||
extern int auth_debug_mode;
|
||||
#endif
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/* $NetBSD: enc-proto.h,v 1.9 2012/01/09 15:25:33 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)enc-proto.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifdef ENCRYPTION
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
Encryptions *findencryption(int);
|
||||
Encryptions *finddecryption(int);
|
||||
void encrypt_init(const char *, int);
|
||||
void encrypt_list_types(void);
|
||||
int EncryptEnable(char *, char *);
|
||||
int EncryptDisable(char *, char *);
|
||||
int EncryptType(char *, char *);
|
||||
int EncryptStart(char *);
|
||||
int EncryptStartInput(void);
|
||||
int EncryptStartOutput(void);
|
||||
int EncryptStop(char *);
|
||||
int EncryptStopInput(void);
|
||||
int EncryptStopOutput(void);
|
||||
int EncryptStatus(void);
|
||||
void encrypt_send_support(void);
|
||||
int EncryptDebug(int);
|
||||
int EncryptVerbose(int);
|
||||
int EncryptAutoEnc(int);
|
||||
int EncryptAutoDec(int);
|
||||
void encrypt_support(unsigned char *, int);
|
||||
void encrypt_is(unsigned char *, int);
|
||||
void encrypt_reply(unsigned char *, int);
|
||||
void encrypt_start(unsigned char *, int);
|
||||
void encrypt_session_key(Session_Key *, int);
|
||||
void encrypt_end(void);
|
||||
void encrypt_request_end(void);
|
||||
void encrypt_request_start(unsigned char *, int);
|
||||
void encrypt_enc_keyid(unsigned char *, int);
|
||||
void encrypt_dec_keyid(unsigned char *, int);
|
||||
struct key_info;
|
||||
void encrypt_keyid(struct key_info *, unsigned char *, int);
|
||||
void encrypt_send_keyid(int, const unsigned char *, int, int);
|
||||
void encrypt_auto(int);
|
||||
void decrypt_auto(int);
|
||||
void encrypt_start_output(int);
|
||||
void encrypt_send_end(void);
|
||||
void encrypt_send_request_start(void);
|
||||
void encrypt_send_request_end(void);
|
||||
void encrypt_wait(void);
|
||||
void encrypt_debug(int);
|
||||
void encrypt_gen_printsub(unsigned char *, int, unsigned char *, int );
|
||||
void encrypt_printsub(unsigned char *, int, unsigned char *, int );
|
||||
|
||||
#ifdef TELENTD
|
||||
void encrypt_wait(void);
|
||||
#else
|
||||
void printsub(int, unsigned char *, int);
|
||||
int encrypt_cmd(int, char **);
|
||||
void encrypt_display(void);
|
||||
#endif
|
||||
|
||||
void krbdes_encrypt(unsigned char *, int);
|
||||
int krbdes_decrypt(int);
|
||||
int krbdes_is(unsigned char *, int);
|
||||
int krbdes_reply(unsigned char *, int);
|
||||
void krbdes_init(int);
|
||||
int krbdes_start(int, int);
|
||||
void krbdes_session(Session_Key *, int);
|
||||
void krbdes_printsub(unsigned char *, int, unsigned char *, int);
|
||||
|
||||
void cfb64_encrypt(unsigned char *, int);
|
||||
int cfb64_decrypt(int);
|
||||
void cfb64_init(int);
|
||||
int cfb64_start(int, int);
|
||||
int cfb64_is(unsigned char *, int);
|
||||
int cfb64_reply(unsigned char *, int);
|
||||
void cfb64_session(Session_Key *, int);
|
||||
int cfb64_keyid(int, unsigned char *, int *);
|
||||
void cfb64_printsub(unsigned char *, int, unsigned char *, int);
|
||||
|
||||
void ofb64_encrypt(unsigned char *, int);
|
||||
int ofb64_decrypt(int);
|
||||
void ofb64_init(int);
|
||||
int ofb64_start(int, int);
|
||||
int ofb64_is(unsigned char *, int);
|
||||
int ofb64_reply(unsigned char *, int);
|
||||
void ofb64_session(Session_Key *, int);
|
||||
int ofb64_keyid(int, unsigned char *, int *);
|
||||
void ofb64_printsub(unsigned char *, int, unsigned char *, int);
|
||||
|
||||
void fb64_printsub(const unsigned char *, int, unsigned char *, int,
|
||||
const unsigned char *);
|
||||
|
||||
#endif /* ENCRYPTION */
|
||||
|
|
@ -1,665 +0,0 @@
|
|||
/* $NetBSD: enc_des.c,v 1.16 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)enc_des.c 8.3 (Berkeley) 5/30/95"; */
|
||||
#else
|
||||
__RCSID("$NetBSD: enc_des.c,v 1.16 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#ifdef ENCRYPTION
|
||||
# ifdef AUTHENTICATION
|
||||
# ifdef DES_ENCRYPTION
|
||||
#include <arpa/telnet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <des.h>
|
||||
#include "encrypt.h"
|
||||
#include "key-proto.h"
|
||||
#include "misc-proto.h"
|
||||
|
||||
#define CFB 0
|
||||
#define OFB 1
|
||||
|
||||
#define NO_SEND_IV 1
|
||||
#define NO_RECV_IV 2
|
||||
#define NO_KEYID 4
|
||||
#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
|
||||
#define SUCCESS 0
|
||||
#define FAILED -1
|
||||
|
||||
|
||||
struct fb {
|
||||
Block krbdes_key;
|
||||
Schedule krbdes_sched;
|
||||
Block temp_feed;
|
||||
unsigned char fb_feed[64];
|
||||
int need_start;
|
||||
int state[2];
|
||||
int keyid[2];
|
||||
int once;
|
||||
struct stinfo {
|
||||
Block str_output;
|
||||
Block str_feed;
|
||||
Block str_iv;
|
||||
Block str_ikey;
|
||||
Schedule str_sched;
|
||||
int str_index;
|
||||
int str_flagshift;
|
||||
} streams[2];
|
||||
};
|
||||
|
||||
static struct fb fb[2];
|
||||
|
||||
struct keyidlist {
|
||||
const char *keyid;
|
||||
int keyidlen;
|
||||
char *key;
|
||||
int keylen;
|
||||
int flags;
|
||||
} keyidlist [] = {
|
||||
{ "\0", 1, 0, 0, 0 }, /* default key of zero */
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#define KEYFLAG_MASK 03
|
||||
|
||||
#define KEYFLAG_NOINIT 00
|
||||
#define KEYFLAG_INIT 01
|
||||
#define KEYFLAG_OK 02
|
||||
#define KEYFLAG_BAD 03
|
||||
|
||||
#define KEYFLAG_SHIFT 2
|
||||
|
||||
#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2)))
|
||||
|
||||
#define FB64_IV 1
|
||||
#define FB64_IV_OK 2
|
||||
#define FB64_IV_BAD 3
|
||||
|
||||
|
||||
void fb64_stream_iv(Block, struct stinfo *);
|
||||
void fb64_init(struct fb *);
|
||||
static int fb64_start(struct fb *, int, int);
|
||||
int fb64_is(unsigned char *, int, struct fb *);
|
||||
int fb64_reply(unsigned char *, int, struct fb *);
|
||||
static void fb64_session(Session_Key *, int, struct fb *);
|
||||
void fb64_stream_key(Block *, struct stinfo *);
|
||||
int fb64_keyid(int, unsigned char *, int *, struct fb *);
|
||||
|
||||
void
|
||||
cfb64_init(int server)
|
||||
{
|
||||
fb64_init(&fb[CFB]);
|
||||
fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
|
||||
fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
|
||||
fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
|
||||
}
|
||||
|
||||
void
|
||||
ofb64_init(int server)
|
||||
{
|
||||
fb64_init(&fb[OFB]);
|
||||
fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
|
||||
fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
|
||||
fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
|
||||
}
|
||||
|
||||
void
|
||||
fb64_init(register struct fb *fbp)
|
||||
{
|
||||
memset((void *)fbp, 0, sizeof(*fbp));
|
||||
fbp->state[0] = fbp->state[1] = FAILED;
|
||||
fbp->fb_feed[0] = IAC;
|
||||
fbp->fb_feed[1] = SB;
|
||||
fbp->fb_feed[2] = TELOPT_ENCRYPT;
|
||||
fbp->fb_feed[3] = ENCRYPT_IS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* -1: some error. Negotiation is done, encryption not ready.
|
||||
* 0: Successful, initial negotiation all done.
|
||||
* 1: successful, negotiation not done yet.
|
||||
* 2: Not yet. Other things (like getting the key from
|
||||
* Kerberos) have to happen before we can continue.
|
||||
*/
|
||||
int
|
||||
cfb64_start(int dir, int server)
|
||||
{
|
||||
return(fb64_start(&fb[CFB], dir, server));
|
||||
}
|
||||
|
||||
int
|
||||
ofb64_start(int dir, int server)
|
||||
{
|
||||
return(fb64_start(&fb[OFB], dir, server));
|
||||
}
|
||||
|
||||
static int
|
||||
fb64_start(struct fb *fbp, int dir, int server)
|
||||
{
|
||||
size_t x;
|
||||
unsigned char *p;
|
||||
register int state;
|
||||
|
||||
switch (dir) {
|
||||
case DIR_DECRYPT:
|
||||
/*
|
||||
* This is simply a request to have the other side
|
||||
* start output (our input). He will negotiate an
|
||||
* IV so we need not look for it.
|
||||
*/
|
||||
state = fbp->state[dir-1];
|
||||
if (state == FAILED)
|
||||
state = IN_PROGRESS;
|
||||
break;
|
||||
|
||||
case DIR_ENCRYPT:
|
||||
state = fbp->state[dir-1];
|
||||
if (state == FAILED)
|
||||
state = IN_PROGRESS;
|
||||
else if ((state & NO_SEND_IV) == 0)
|
||||
break;
|
||||
|
||||
if (!VALIDKEY(fbp->krbdes_key)) {
|
||||
fbp->need_start = 1;
|
||||
break;
|
||||
}
|
||||
state &= ~NO_SEND_IV;
|
||||
state |= NO_RECV_IV;
|
||||
if (encrypt_debug_mode)
|
||||
printf("Creating new feed\r\n");
|
||||
/*
|
||||
* Create a random feed and send it over.
|
||||
*/
|
||||
des_new_random_key(&fbp->temp_feed);
|
||||
des_ecb_encrypt(&fbp->temp_feed, &fbp->temp_feed,
|
||||
fbp->krbdes_sched, 1);
|
||||
p = fbp->fb_feed + 3;
|
||||
*p++ = ENCRYPT_IS;
|
||||
p++;
|
||||
*p++ = FB64_IV;
|
||||
for (x = 0; x < sizeof(Block); ++x) {
|
||||
if ((*p++ = fbp->temp_feed[x]) == IAC)
|
||||
*p++ = IAC;
|
||||
}
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
|
||||
telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
|
||||
break;
|
||||
default:
|
||||
return(FAILED);
|
||||
}
|
||||
return(fbp->state[dir-1] = state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* -1: some error. Negotiation is done, encryption not ready.
|
||||
* 0: Successful, initial negotiation all done.
|
||||
* 1: successful, negotiation not done yet.
|
||||
*/
|
||||
int
|
||||
cfb64_is(unsigned char *data, int cnt)
|
||||
{
|
||||
return(fb64_is(data, cnt, &fb[CFB]));
|
||||
}
|
||||
int
|
||||
ofb64_is(unsigned char *data, int cnt)
|
||||
{
|
||||
return(fb64_is(data, cnt, &fb[OFB]));
|
||||
}
|
||||
|
||||
int
|
||||
fb64_is(unsigned char *data, int cnt, struct fb *fbp)
|
||||
{
|
||||
unsigned char *p;
|
||||
register int state = fbp->state[DIR_DECRYPT-1];
|
||||
|
||||
if (cnt-- < 1)
|
||||
goto failure;
|
||||
|
||||
switch (*data++) {
|
||||
case FB64_IV:
|
||||
if (cnt != sizeof(Block)) {
|
||||
if (encrypt_debug_mode)
|
||||
printf("CFB64: initial vector failed on size\r\n");
|
||||
state = FAILED;
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (encrypt_debug_mode)
|
||||
printf("CFB64: initial vector received\r\n");
|
||||
|
||||
if (encrypt_debug_mode)
|
||||
printf("Initializing Decrypt stream\r\n");
|
||||
|
||||
fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
|
||||
|
||||
p = fbp->fb_feed + 3;
|
||||
*p++ = ENCRYPT_REPLY;
|
||||
p++;
|
||||
*p++ = FB64_IV_OK;
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
|
||||
telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
|
||||
|
||||
state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (encrypt_debug_mode) {
|
||||
printf("Unknown option type: %d\r\n", *(data-1));
|
||||
printd(data, cnt);
|
||||
printf("\r\n");
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
failure:
|
||||
/*
|
||||
* We failed. Send an FB64_IV_BAD option
|
||||
* to the other side so it will know that
|
||||
* things failed.
|
||||
*/
|
||||
p = fbp->fb_feed + 3;
|
||||
*p++ = ENCRYPT_REPLY;
|
||||
p++;
|
||||
*p++ = FB64_IV_BAD;
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
|
||||
telnet_net_write(fbp->fb_feed, p - fbp->fb_feed);
|
||||
|
||||
break;
|
||||
}
|
||||
return(fbp->state[DIR_DECRYPT-1] = state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* -1: some error. Negotiation is done, encryption not ready.
|
||||
* 0: Successful, initial negotiation all done.
|
||||
* 1: successful, negotiation not done yet.
|
||||
*/
|
||||
int
|
||||
cfb64_reply(unsigned char *data, int cnt)
|
||||
{
|
||||
return(fb64_reply(data, cnt, &fb[CFB]));
|
||||
}
|
||||
int
|
||||
ofb64_reply(unsigned char *data, int cnt)
|
||||
{
|
||||
return(fb64_reply(data, cnt, &fb[OFB]));
|
||||
}
|
||||
|
||||
int
|
||||
fb64_reply(unsigned char *data, int cnt, struct fb *fbp)
|
||||
{
|
||||
register int state = fbp->state[DIR_ENCRYPT-1];
|
||||
|
||||
if (cnt-- < 1)
|
||||
goto failure;
|
||||
|
||||
switch (*data++) {
|
||||
case FB64_IV_OK:
|
||||
fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
|
||||
if (state == FAILED)
|
||||
state = IN_PROGRESS;
|
||||
state &= ~NO_RECV_IV;
|
||||
encrypt_send_keyid(DIR_ENCRYPT, (const unsigned char *)"\0", 1, 1);
|
||||
break;
|
||||
|
||||
case FB64_IV_BAD:
|
||||
memset(fbp->temp_feed, 0, sizeof(Block));
|
||||
fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
|
||||
state = FAILED;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (encrypt_debug_mode) {
|
||||
printf("Unknown option type: %d\r\n", data[-1]);
|
||||
printd(data, cnt);
|
||||
printf("\r\n");
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
failure:
|
||||
state = FAILED;
|
||||
break;
|
||||
}
|
||||
return(fbp->state[DIR_ENCRYPT-1] = state);
|
||||
}
|
||||
|
||||
void
|
||||
cfb64_session(Session_Key *key, int server)
|
||||
{
|
||||
fb64_session(key, server, &fb[CFB]);
|
||||
}
|
||||
|
||||
void
|
||||
ofb64_session( Session_Key *key, int server)
|
||||
{
|
||||
fb64_session(key, server, &fb[OFB]);
|
||||
}
|
||||
|
||||
static void
|
||||
fb64_session(Session_Key *key, int server, struct fb *fbp)
|
||||
{
|
||||
|
||||
if (!key || key->type != SK_DES) {
|
||||
if (encrypt_debug_mode)
|
||||
printf("Can't set krbdes's session key (%d != %d)\r\n",
|
||||
key ? key->type : -1, SK_DES);
|
||||
return;
|
||||
}
|
||||
memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
|
||||
|
||||
fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
|
||||
fb64_stream_key(&fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
|
||||
|
||||
if (fbp->once == 0) {
|
||||
des_init_random_number_generator(&fbp->krbdes_key);
|
||||
fbp->once = 1;
|
||||
}
|
||||
des_key_sched(&fbp->krbdes_key, fbp->krbdes_sched);
|
||||
/*
|
||||
* Now look to see if krbdes_start() was waiting for the key to
|
||||
* show up. If so, go ahead an call it now that we have the key.
|
||||
*/
|
||||
if (fbp->need_start) {
|
||||
fbp->need_start = 0;
|
||||
fb64_start(fbp, DIR_ENCRYPT, server);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We only accept a keyid of 0. If we get a keyid of
|
||||
* 0, then mark the state as SUCCESS.
|
||||
*/
|
||||
int
|
||||
cfb64_keyid(int dir, unsigned char *kp, int *lenp)
|
||||
{
|
||||
return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
|
||||
}
|
||||
|
||||
int
|
||||
ofb64_keyid(int dir, unsigned char *kp, int *lenp)
|
||||
{
|
||||
return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
|
||||
}
|
||||
|
||||
int
|
||||
fb64_keyid(int dir, unsigned char *kp, int *lenp, struct fb *fbp)
|
||||
{
|
||||
register int state = fbp->state[dir-1];
|
||||
|
||||
if (*lenp != 1 || (*kp != '\0')) {
|
||||
*lenp = 0;
|
||||
return(state);
|
||||
}
|
||||
|
||||
if (state == FAILED)
|
||||
state = IN_PROGRESS;
|
||||
|
||||
state &= ~NO_KEYID;
|
||||
|
||||
return(fbp->state[dir-1] = state);
|
||||
}
|
||||
|
||||
void
|
||||
fb64_printsub(const unsigned char *data, int cnt, unsigned char *buf,
|
||||
int buflen, const unsigned char *type)
|
||||
{
|
||||
char lbuf[32];
|
||||
register int i;
|
||||
char *cp;
|
||||
|
||||
buf[buflen-1] = '\0'; /* make sure it's NULL terminated */
|
||||
buflen -= 1;
|
||||
|
||||
switch(data[2]) {
|
||||
case FB64_IV:
|
||||
snprintf(lbuf, sizeof(lbuf), "%s_IV", type);
|
||||
cp = lbuf;
|
||||
goto common;
|
||||
|
||||
case FB64_IV_OK:
|
||||
snprintf(lbuf, sizeof(lbuf), "%s_IV_OK", type);
|
||||
cp = lbuf;
|
||||
goto common;
|
||||
|
||||
case FB64_IV_BAD:
|
||||
snprintf(lbuf, sizeof(lbuf), "%s_IV_BAD", type);
|
||||
cp = lbuf;
|
||||
goto common;
|
||||
|
||||
default:
|
||||
snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[2]);
|
||||
cp = lbuf;
|
||||
common:
|
||||
for (; (buflen > 0) && (*buf = *cp++); buf++)
|
||||
buflen--;
|
||||
for (i = 3; i < cnt; i++) {
|
||||
snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
|
||||
for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
|
||||
buflen--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cfb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
|
||||
{
|
||||
fb64_printsub(data, cnt, buf, buflen, "CFB64");
|
||||
}
|
||||
|
||||
void
|
||||
ofb64_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
|
||||
{
|
||||
fb64_printsub(data, cnt, buf, buflen, "OFB64");
|
||||
}
|
||||
|
||||
void
|
||||
fb64_stream_iv(Block seed, struct stinfo *stp)
|
||||
{
|
||||
|
||||
memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
|
||||
memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
|
||||
|
||||
des_key_sched(&stp->str_ikey, stp->str_sched);
|
||||
|
||||
stp->str_index = sizeof(Block);
|
||||
}
|
||||
|
||||
void
|
||||
fb64_stream_key(Block *key, struct stinfo *stp)
|
||||
{
|
||||
memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
|
||||
des_key_sched(key, stp->str_sched);
|
||||
|
||||
memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
|
||||
|
||||
stp->str_index = sizeof(Block);
|
||||
}
|
||||
|
||||
/*
|
||||
* DES 64 bit Cipher Feedback
|
||||
*
|
||||
* key --->+-----+
|
||||
* +->| DES |--+
|
||||
* | +-----+ |
|
||||
* | v
|
||||
* INPUT --(--------->(+)+---> DATA
|
||||
* | |
|
||||
* +-------------+
|
||||
*
|
||||
*
|
||||
* Given:
|
||||
* iV: Initial vector, 64 bits (8 bytes) long.
|
||||
* Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
|
||||
* On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
|
||||
*
|
||||
* V0 = DES(iV, key)
|
||||
* On = Dn ^ Vn
|
||||
* V(n+1) = DES(On, key)
|
||||
*/
|
||||
|
||||
void
|
||||
cfb64_encrypt(unsigned char *s, int c)
|
||||
{
|
||||
register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
|
||||
register int idx;
|
||||
|
||||
idx = stp->str_index;
|
||||
while (c-- > 0) {
|
||||
if (idx == sizeof(Block)) {
|
||||
Block b;
|
||||
des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
|
||||
memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
/* On encryption, we store (feed ^ data) which is cypher */
|
||||
*s = stp->str_output[idx] = (stp->str_feed[idx] ^ *s);
|
||||
s++;
|
||||
idx++;
|
||||
}
|
||||
stp->str_index = idx;
|
||||
}
|
||||
|
||||
int
|
||||
cfb64_decrypt(int data)
|
||||
{
|
||||
register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
|
||||
int idx;
|
||||
|
||||
if (data == -1) {
|
||||
/*
|
||||
* Back up one byte. It is assumed that we will
|
||||
* never back up more than one byte. If we do, this
|
||||
* may or may not work.
|
||||
*/
|
||||
if (stp->str_index)
|
||||
--stp->str_index;
|
||||
return(0);
|
||||
}
|
||||
|
||||
idx = stp->str_index++;
|
||||
if (idx == sizeof(Block)) {
|
||||
Block b;
|
||||
des_ecb_encrypt(&stp->str_output, &b, stp->str_sched, 1);
|
||||
memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
|
||||
stp->str_index = 1; /* Next time will be 1 */
|
||||
idx = 0; /* But now use 0 */
|
||||
}
|
||||
|
||||
/* On decryption we store (data) which is cypher. */
|
||||
stp->str_output[idx] = data;
|
||||
return(data ^ stp->str_feed[idx]);
|
||||
}
|
||||
|
||||
/*
|
||||
* DES 64 bit Output Feedback
|
||||
*
|
||||
* key --->+-----+
|
||||
* +->| DES |--+
|
||||
* | +-----+ |
|
||||
* +-----------+
|
||||
* v
|
||||
* INPUT -------->(+) ----> DATA
|
||||
*
|
||||
* Given:
|
||||
* iV: Initial vector, 64 bits (8 bytes) long.
|
||||
* Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
|
||||
* On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
|
||||
*
|
||||
* V0 = DES(iV, key)
|
||||
* V(n+1) = DES(Vn, key)
|
||||
* On = Dn ^ Vn
|
||||
*/
|
||||
void
|
||||
ofb64_encrypt(unsigned char *s, int c)
|
||||
{
|
||||
register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
|
||||
register int idx;
|
||||
|
||||
idx = stp->str_index;
|
||||
while (c-- > 0) {
|
||||
if (idx == sizeof(Block)) {
|
||||
Block b;
|
||||
des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
|
||||
memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
|
||||
idx = 0;
|
||||
}
|
||||
*s++ ^= stp->str_feed[idx];
|
||||
idx++;
|
||||
}
|
||||
stp->str_index = idx;
|
||||
}
|
||||
|
||||
int
|
||||
ofb64_decrypt(int data)
|
||||
{
|
||||
register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
|
||||
int idx;
|
||||
|
||||
if (data == -1) {
|
||||
/*
|
||||
* Back up one byte. It is assumed that we will
|
||||
* never back up more than one byte. If we do, this
|
||||
* may or may not work.
|
||||
*/
|
||||
if (stp->str_index)
|
||||
--stp->str_index;
|
||||
return(0);
|
||||
}
|
||||
|
||||
idx = stp->str_index++;
|
||||
if (idx == sizeof(Block)) {
|
||||
Block b;
|
||||
des_ecb_encrypt(&stp->str_feed, &b, stp->str_sched, 1);
|
||||
memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
|
||||
stp->str_index = 1; /* Next time will be 1 */
|
||||
idx = 0; /* But now use 0 */
|
||||
}
|
||||
|
||||
return(data ^ stp->str_feed[idx]);
|
||||
}
|
||||
# endif /* DES_ENCRYPTION */
|
||||
# endif /* AUTHENTICATION */
|
||||
#endif /* ENCRYPTION */
|
||||
|
|
@ -1,960 +0,0 @@
|
|||
/* $NetBSD: encrypt.c,v 1.17 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)encrypt.c 8.2 (Berkeley) 5/30/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: encrypt.c,v 1.17 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifdef ENCRYPTION
|
||||
|
||||
#include <stdio.h>
|
||||
#define ENCRYPT_NAMES
|
||||
#include <arpa/telnet.h>
|
||||
|
||||
#include "encrypt.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef NO_STRING_H
|
||||
#include <strings.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These functions pointers point to the current routines
|
||||
* for encrypting and decrypting data.
|
||||
*/
|
||||
void (*encrypt_output)(unsigned char *, int);
|
||||
int (*decrypt_input)(int);
|
||||
|
||||
int encrypt_debug_mode = 0;
|
||||
static int decrypt_mode = 0;
|
||||
static int encrypt_mode = 0;
|
||||
static int encrypt_verbose = 0;
|
||||
static int autoencrypt = 0;
|
||||
static int autodecrypt = 0;
|
||||
static int havesessionkey = 0;
|
||||
static int Server = 0;
|
||||
static const char *Name = "Noname";
|
||||
|
||||
#define typemask(x) ((x) > 0 ? 1 << ((x)-1) : 0)
|
||||
|
||||
static long i_support_encrypt = typemask(ENCTYPE_DES_CFB64)
|
||||
| typemask(ENCTYPE_DES_OFB64);
|
||||
static long i_support_decrypt = typemask(ENCTYPE_DES_CFB64)
|
||||
| typemask(ENCTYPE_DES_OFB64);
|
||||
static long i_wont_support_encrypt = 0;
|
||||
static long i_wont_support_decrypt = 0;
|
||||
#define I_SUPPORT_ENCRYPT (i_support_encrypt & ~i_wont_support_encrypt)
|
||||
#define I_SUPPORT_DECRYPT (i_support_decrypt & ~i_wont_support_decrypt)
|
||||
|
||||
static long remote_supports_encrypt = 0;
|
||||
static long remote_supports_decrypt = 0;
|
||||
|
||||
static Encryptions encryptions[] = {
|
||||
#ifdef DES_ENCRYPTION
|
||||
{ "DES_CFB64", ENCTYPE_DES_CFB64,
|
||||
cfb64_encrypt,
|
||||
cfb64_decrypt,
|
||||
cfb64_init,
|
||||
cfb64_start,
|
||||
cfb64_is,
|
||||
cfb64_reply,
|
||||
cfb64_session,
|
||||
cfb64_keyid,
|
||||
cfb64_printsub },
|
||||
{ "DES_OFB64", ENCTYPE_DES_OFB64,
|
||||
ofb64_encrypt,
|
||||
ofb64_decrypt,
|
||||
ofb64_init,
|
||||
ofb64_start,
|
||||
ofb64_is,
|
||||
ofb64_reply,
|
||||
ofb64_session,
|
||||
ofb64_keyid,
|
||||
ofb64_printsub },
|
||||
#endif /* DES_ENCRYPTION */
|
||||
{ .name = 0 },
|
||||
};
|
||||
|
||||
static unsigned char str_send[64] = { IAC, SB, TELOPT_ENCRYPT,
|
||||
ENCRYPT_SUPPORT };
|
||||
static unsigned char str_suplen = 0;
|
||||
static unsigned char str_start[72] = { IAC, SB, TELOPT_ENCRYPT };
|
||||
static unsigned char str_end[] = { IAC, SB, TELOPT_ENCRYPT, 0, IAC, SE };
|
||||
|
||||
Encryptions *
|
||||
findencryption(int type)
|
||||
{
|
||||
Encryptions *ep = encryptions;
|
||||
|
||||
if (!(I_SUPPORT_ENCRYPT & remote_supports_decrypt & typemask(type)))
|
||||
return(0);
|
||||
while (ep->type && ep->type != type)
|
||||
++ep;
|
||||
return(ep->type ? ep : 0);
|
||||
}
|
||||
|
||||
Encryptions *
|
||||
finddecryption(int type)
|
||||
{
|
||||
Encryptions *ep = encryptions;
|
||||
|
||||
if (!(I_SUPPORT_DECRYPT & remote_supports_encrypt & typemask(type)))
|
||||
return(0);
|
||||
while (ep->type && ep->type != type)
|
||||
++ep;
|
||||
return(ep->type ? ep : 0);
|
||||
}
|
||||
|
||||
#define MAXKEYLEN 64
|
||||
|
||||
static struct key_info {
|
||||
unsigned char keyid[MAXKEYLEN];
|
||||
int keylen;
|
||||
int dir;
|
||||
int *modep;
|
||||
Encryptions *(*getcrypt)(int);
|
||||
} ki[2] = {
|
||||
{ { 0 }, 0, DIR_ENCRYPT, &encrypt_mode, findencryption },
|
||||
{ { 0 }, 0, DIR_DECRYPT, &decrypt_mode, finddecryption },
|
||||
};
|
||||
|
||||
void
|
||||
encrypt_init(const char *name, int server)
|
||||
{
|
||||
Encryptions *ep = encryptions;
|
||||
|
||||
Name = name;
|
||||
Server = server;
|
||||
i_support_encrypt = i_support_decrypt = 0;
|
||||
remote_supports_encrypt = remote_supports_decrypt = 0;
|
||||
encrypt_mode = 0;
|
||||
decrypt_mode = 0;
|
||||
encrypt_output = 0;
|
||||
decrypt_input = 0;
|
||||
#ifdef notdef
|
||||
encrypt_verbose = !server;
|
||||
#endif
|
||||
|
||||
str_suplen = 4;
|
||||
|
||||
while (ep->type) {
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: I will support %s\r\n",
|
||||
Name, ENCTYPE_NAME(ep->type));
|
||||
i_support_encrypt |= typemask(ep->type);
|
||||
i_support_decrypt |= typemask(ep->type);
|
||||
if ((i_wont_support_decrypt & typemask(ep->type)) == 0)
|
||||
if ((str_send[str_suplen++] = ep->type) == IAC)
|
||||
str_send[str_suplen++] = IAC;
|
||||
if (ep->init)
|
||||
(*ep->init)(Server);
|
||||
++ep;
|
||||
}
|
||||
str_send[str_suplen++] = IAC;
|
||||
str_send[str_suplen++] = SE;
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_list_types(void)
|
||||
{
|
||||
Encryptions *ep = encryptions;
|
||||
|
||||
printf("Valid encryption types:\n");
|
||||
while (ep->type) {
|
||||
printf("\t%s (%d)\r\n", ENCTYPE_NAME(ep->type), ep->type);
|
||||
++ep;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EncryptEnable(char *type, char *mode)
|
||||
{
|
||||
if (isprefix(type, "help") || isprefix(type, "?")) {
|
||||
printf("Usage: encrypt enable <type> [input|output]\n");
|
||||
encrypt_list_types();
|
||||
return(0);
|
||||
}
|
||||
if (EncryptType(type, mode))
|
||||
return(EncryptStart(mode));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptDisable(char *type, char *mode)
|
||||
{
|
||||
register Encryptions *ep;
|
||||
int ret = 0;
|
||||
|
||||
if (isprefix(type, "help") || isprefix(type, "?")) {
|
||||
printf("Usage: encrypt disable <type> [input|output]\n");
|
||||
encrypt_list_types();
|
||||
} else if ((ep = (Encryptions *)genget(type, (char **)encryptions,
|
||||
sizeof(Encryptions))) == 0) {
|
||||
printf("%s: invalid encryption type\n", type);
|
||||
} else if (Ambiguous(ep)) {
|
||||
printf("Ambiguous type '%s'\n", type);
|
||||
} else {
|
||||
if ((mode == 0) || (isprefix(mode, "input") ? 1 : 0)) {
|
||||
if (decrypt_mode == ep->type)
|
||||
EncryptStopInput();
|
||||
i_wont_support_decrypt |= typemask(ep->type);
|
||||
ret = 1;
|
||||
}
|
||||
if ((mode == 0) || (isprefix(mode, "output"))) {
|
||||
if (encrypt_mode == ep->type)
|
||||
EncryptStopOutput();
|
||||
i_wont_support_encrypt |= typemask(ep->type);
|
||||
ret = 1;
|
||||
}
|
||||
if (ret == 0)
|
||||
printf("%s: invalid encryption mode\n", mode);
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptType(char *type, char *mode)
|
||||
{
|
||||
register Encryptions *ep;
|
||||
int ret = 0;
|
||||
|
||||
if (isprefix(type, "help") || isprefix(type, "?")) {
|
||||
printf("Usage: encrypt type <type> [input|output]\n");
|
||||
encrypt_list_types();
|
||||
} else if ((ep = (Encryptions *)genget(type, (char **)encryptions,
|
||||
sizeof(Encryptions))) == 0) {
|
||||
printf("%s: invalid encryption type\n", type);
|
||||
} else if (Ambiguous(ep)) {
|
||||
printf("Ambiguous type '%s'\n", type);
|
||||
} else {
|
||||
if ((mode == 0) || isprefix(mode, "input")) {
|
||||
decrypt_mode = ep->type;
|
||||
i_wont_support_decrypt &= ~typemask(ep->type);
|
||||
ret = 1;
|
||||
}
|
||||
if ((mode == 0) || isprefix(mode, "output")) {
|
||||
encrypt_mode = ep->type;
|
||||
i_wont_support_encrypt &= ~typemask(ep->type);
|
||||
ret = 1;
|
||||
}
|
||||
if (ret == 0)
|
||||
printf("%s: invalid encryption mode\n", mode);
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStart(char *mode)
|
||||
{
|
||||
register int ret = 0;
|
||||
if (mode) {
|
||||
if (isprefix(mode, "input"))
|
||||
return(EncryptStartInput());
|
||||
if (isprefix(mode, "output"))
|
||||
return(EncryptStartOutput());
|
||||
if (isprefix(mode, "help") || isprefix(mode, "?")) {
|
||||
printf("Usage: encrypt start [input|output]\n");
|
||||
return(0);
|
||||
}
|
||||
printf("%s: invalid encryption mode 'encrypt start ?' for help\n", mode);
|
||||
return(0);
|
||||
}
|
||||
ret += EncryptStartInput();
|
||||
ret += EncryptStartOutput();
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStartInput(void)
|
||||
{
|
||||
if (decrypt_mode) {
|
||||
encrypt_send_request_start();
|
||||
return(1);
|
||||
}
|
||||
printf("No previous decryption mode, decryption not enabled\r\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStartOutput(void)
|
||||
{
|
||||
if (encrypt_mode) {
|
||||
encrypt_start_output(encrypt_mode);
|
||||
return(1);
|
||||
}
|
||||
printf("No previous encryption mode, encryption not enabled\r\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStop(char *mode)
|
||||
{
|
||||
int ret = 0;
|
||||
if (mode) {
|
||||
if (isprefix(mode, "input"))
|
||||
return(EncryptStopInput());
|
||||
if (isprefix(mode, "output"))
|
||||
return(EncryptStopOutput());
|
||||
if (isprefix(mode, "help") || isprefix(mode, "?")) {
|
||||
printf("Usage: encrypt stop [input|output]\n");
|
||||
return(0);
|
||||
}
|
||||
printf("%s: invalid encryption mode 'encrypt stop ?' for help\n", mode);
|
||||
return(0);
|
||||
}
|
||||
ret += EncryptStopInput();
|
||||
ret += EncryptStopOutput();
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStopInput(void)
|
||||
{
|
||||
encrypt_send_request_end();
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStopOutput(void)
|
||||
{
|
||||
encrypt_send_end();
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_display(void)
|
||||
{
|
||||
if (encrypt_output)
|
||||
printf("Currently encrypting output with %s\r\n",
|
||||
ENCTYPE_NAME(encrypt_mode));
|
||||
if (decrypt_input)
|
||||
printf("Currently decrypting input with %s\r\n",
|
||||
ENCTYPE_NAME(decrypt_mode));
|
||||
}
|
||||
|
||||
int
|
||||
EncryptStatus(void)
|
||||
{
|
||||
if (encrypt_output)
|
||||
printf("Currently encrypting output with %s\r\n",
|
||||
ENCTYPE_NAME(encrypt_mode));
|
||||
else if (encrypt_mode) {
|
||||
printf("Currently output is clear text.\r\n");
|
||||
printf("Last encryption mode was %s\r\n",
|
||||
ENCTYPE_NAME(encrypt_mode));
|
||||
}
|
||||
if (decrypt_input) {
|
||||
printf("Currently decrypting input with %s\r\n",
|
||||
ENCTYPE_NAME(decrypt_mode));
|
||||
} else if (decrypt_mode) {
|
||||
printf("Currently input is clear text.\r\n");
|
||||
printf("Last decryption mode was %s\r\n",
|
||||
ENCTYPE_NAME(decrypt_mode));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_send_support(void)
|
||||
{
|
||||
if (str_suplen) {
|
||||
/*
|
||||
* If the user has requested that decryption start
|
||||
* immediatly, then send a "REQUEST START" before
|
||||
* we negotiate the type.
|
||||
*/
|
||||
if (!Server && autodecrypt)
|
||||
encrypt_send_request_start();
|
||||
telnet_net_write(str_send, str_suplen);
|
||||
printsub('>', &str_send[2], str_suplen - 2);
|
||||
str_suplen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EncryptDebug(int on)
|
||||
{
|
||||
if (on < 0)
|
||||
encrypt_debug_mode ^= 1;
|
||||
else
|
||||
encrypt_debug_mode = on;
|
||||
printf("Encryption debugging %s\r\n",
|
||||
encrypt_debug_mode ? "enabled" : "disabled");
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptVerbose(int on)
|
||||
{
|
||||
if (on < 0)
|
||||
encrypt_verbose ^= 1;
|
||||
else
|
||||
encrypt_verbose = on;
|
||||
printf("Encryption %s verbose\r\n",
|
||||
encrypt_verbose ? "is" : "is not");
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptAutoEnc(int on)
|
||||
{
|
||||
encrypt_auto(on);
|
||||
printf("Automatic encryption of output is %s\r\n",
|
||||
autoencrypt ? "enabled" : "disabled");
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
EncryptAutoDec(int on)
|
||||
{
|
||||
decrypt_auto(on);
|
||||
printf("Automatic decryption of input is %s\r\n",
|
||||
autodecrypt ? "enabled" : "disabled");
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when ENCRYPT SUPPORT is received.
|
||||
*/
|
||||
void
|
||||
encrypt_support(unsigned char *typelist, int cnt)
|
||||
{
|
||||
register int type, use_type = 0;
|
||||
Encryptions *ep;
|
||||
|
||||
/*
|
||||
* Forget anything the other side has previously told us.
|
||||
*/
|
||||
remote_supports_decrypt = 0;
|
||||
|
||||
while (cnt-- > 0) {
|
||||
type = *typelist++;
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: He is supporting %s (%d)\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME(type), type);
|
||||
if ((type < ENCTYPE_CNT) &&
|
||||
(I_SUPPORT_ENCRYPT & typemask(type))) {
|
||||
remote_supports_decrypt |= typemask(type);
|
||||
if (use_type == 0)
|
||||
use_type = type;
|
||||
}
|
||||
}
|
||||
if (use_type) {
|
||||
ep = findencryption(use_type);
|
||||
if (!ep)
|
||||
return;
|
||||
type = ep->start ? (*ep->start)(DIR_ENCRYPT, Server) : 0;
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: (*ep->start)() returned %d\r\n",
|
||||
Name, type);
|
||||
if (type < 0)
|
||||
return;
|
||||
encrypt_mode = use_type;
|
||||
if (type == 0)
|
||||
encrypt_start_output(use_type);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_is(unsigned char *data, int cnt)
|
||||
{
|
||||
Encryptions *ep;
|
||||
register int type, ret;
|
||||
|
||||
if (--cnt < 0)
|
||||
return;
|
||||
type = *data++;
|
||||
if (type < ENCTYPE_CNT)
|
||||
remote_supports_encrypt |= typemask(type);
|
||||
if (!(ep = finddecryption(type))) {
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(type)
|
||||
? ENCTYPE_NAME(type) : "(unknown)",
|
||||
type);
|
||||
return;
|
||||
}
|
||||
if (!ep->is) {
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(type)
|
||||
? ENCTYPE_NAME(type) : "(unknown)",
|
||||
type);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = (*ep->is)(data, cnt);
|
||||
if (encrypt_debug_mode)
|
||||
printf("(*ep->is)(%p, %d) returned %s(%d)\n", data, cnt,
|
||||
(ret < 0) ? "FAIL " :
|
||||
(ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
|
||||
}
|
||||
if (ret < 0) {
|
||||
autodecrypt = 0;
|
||||
} else {
|
||||
decrypt_mode = type;
|
||||
if (ret == 0 && autodecrypt)
|
||||
encrypt_send_request_start();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_reply(unsigned char *data, int cnt)
|
||||
{
|
||||
Encryptions *ep;
|
||||
register int ret, type;
|
||||
|
||||
if (--cnt < 0)
|
||||
return;
|
||||
type = *data++;
|
||||
if (!(ep = findencryption(type))) {
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Can't find type %s (%d) for initial negotiation\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(type)
|
||||
? ENCTYPE_NAME(type) : "(unknown)",
|
||||
type);
|
||||
return;
|
||||
}
|
||||
if (!ep->reply) {
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: No initial negotiation needed for type %s (%d)\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(type)
|
||||
? ENCTYPE_NAME(type) : "(unknown)",
|
||||
type);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = (*ep->reply)(data, cnt);
|
||||
if (encrypt_debug_mode)
|
||||
printf("(*ep->reply)(%p, %d) returned %s(%d)\n",
|
||||
data, cnt,
|
||||
(ret < 0) ? "FAIL " :
|
||||
(ret == 0) ? "SUCCESS " : "MORE_TO_DO ", ret);
|
||||
}
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: encrypt_reply returned %d\n", Name, ret);
|
||||
if (ret < 0) {
|
||||
autoencrypt = 0;
|
||||
} else {
|
||||
encrypt_mode = type;
|
||||
if (ret == 0 && autoencrypt)
|
||||
encrypt_start_output(type);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a ENCRYPT START command is received.
|
||||
*/
|
||||
void
|
||||
encrypt_start(unsigned char *data, int cnt)
|
||||
{
|
||||
Encryptions *ep;
|
||||
|
||||
if (!decrypt_mode) {
|
||||
/*
|
||||
* Something is wrong. We should not get a START
|
||||
* command without having already picked our
|
||||
* decryption scheme. Send a REQUEST-END to
|
||||
* attempt to clear the channel...
|
||||
*/
|
||||
printf("%s: Warning, Cannot decrypt input stream!!!\r\n", Name);
|
||||
encrypt_send_request_end();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ep = finddecryption(decrypt_mode)) != NULL) {
|
||||
decrypt_input = ep->input;
|
||||
if (encrypt_verbose)
|
||||
printf("[ Input is now decrypted with type %s ]\r\n",
|
||||
ENCTYPE_NAME(decrypt_mode));
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Start to decrypt input with type %s\r\n",
|
||||
Name, ENCTYPE_NAME(decrypt_mode));
|
||||
} else {
|
||||
printf("%s: Warning, Cannot decrypt type %s (%d)!!!\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(decrypt_mode)
|
||||
? ENCTYPE_NAME(decrypt_mode)
|
||||
: "(unknown)",
|
||||
decrypt_mode);
|
||||
encrypt_send_request_end();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_session_key(Session_Key *key, int server)
|
||||
{
|
||||
Encryptions *ep = encryptions;
|
||||
|
||||
havesessionkey = 1;
|
||||
|
||||
while (ep->type) {
|
||||
if (ep->session)
|
||||
(*ep->session)(key, server);
|
||||
#ifdef notdef
|
||||
if (!encrypt_output && autoencrypt && !server)
|
||||
encrypt_start_output(ep->type);
|
||||
if (!decrypt_input && autodecrypt && !server)
|
||||
encrypt_send_request_start();
|
||||
#endif
|
||||
++ep;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when ENCRYPT END is received.
|
||||
*/
|
||||
void
|
||||
encrypt_end(void)
|
||||
{
|
||||
decrypt_input = 0;
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Input is back to clear text\r\n", Name);
|
||||
if (encrypt_verbose)
|
||||
printf("[ Input is now clear text ]\r\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when ENCRYPT REQUEST-END is received.
|
||||
*/
|
||||
void
|
||||
encrypt_request_end(void)
|
||||
{
|
||||
encrypt_send_end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when ENCRYPT REQUEST-START is received. If we receive
|
||||
* this before a type is picked, then that indicates that the
|
||||
* other side wants us to start encrypting data as soon as we
|
||||
* can.
|
||||
*/
|
||||
void
|
||||
encrypt_request_start(unsigned char *data, int cnt)
|
||||
{
|
||||
if (encrypt_mode == 0) {
|
||||
if (Server)
|
||||
autoencrypt = 1;
|
||||
return;
|
||||
}
|
||||
encrypt_start_output(encrypt_mode);
|
||||
}
|
||||
|
||||
static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT };
|
||||
|
||||
void
|
||||
encrypt_enc_keyid(unsigned char *keyid, int len)
|
||||
{
|
||||
encrypt_keyid(&ki[1], keyid, len);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_dec_keyid(unsigned char *keyid, int len)
|
||||
{
|
||||
encrypt_keyid(&ki[0], keyid, len);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_keyid(struct key_info *kp, unsigned char *keyid, int len)
|
||||
{
|
||||
Encryptions *ep;
|
||||
int dir = kp->dir;
|
||||
register int ret = 0;
|
||||
|
||||
if (!(ep = (*kp->getcrypt)(*kp->modep))) {
|
||||
if (len == 0)
|
||||
return;
|
||||
kp->keylen = 0;
|
||||
} else if (len == 0) {
|
||||
/*
|
||||
* Empty option, indicates a failure.
|
||||
*/
|
||||
if (kp->keylen == 0)
|
||||
return;
|
||||
kp->keylen = 0;
|
||||
if (ep->keyid)
|
||||
(void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
|
||||
|
||||
} else if ((size_t)len > sizeof(kp->keyid)) {
|
||||
return;
|
||||
} else if ((len != kp->keylen) ||
|
||||
(memcmp(keyid, kp->keyid, len) != 0)) {
|
||||
/*
|
||||
* Length or contents are different
|
||||
*/
|
||||
kp->keylen = len;
|
||||
memmove(kp->keyid, keyid, len);
|
||||
if (ep->keyid)
|
||||
(void)(*ep->keyid)(dir, kp->keyid, &kp->keylen);
|
||||
} else {
|
||||
if (ep->keyid)
|
||||
ret = (*ep->keyid)(dir, kp->keyid, &kp->keylen);
|
||||
if ((ret == 0) && (dir == DIR_ENCRYPT) && autoencrypt)
|
||||
encrypt_start_output(*kp->modep);
|
||||
return;
|
||||
}
|
||||
|
||||
encrypt_send_keyid(dir, kp->keyid, kp->keylen, 0);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_send_keyid(int dir, const unsigned char *keyid, int keylen, int saveit)
|
||||
{
|
||||
unsigned char *strp;
|
||||
|
||||
str_keyid[3] = (dir == DIR_ENCRYPT)
|
||||
? ENCRYPT_ENC_KEYID : ENCRYPT_DEC_KEYID;
|
||||
if (saveit) {
|
||||
struct key_info *kp = &ki[(dir == DIR_ENCRYPT) ? 0 : 1];
|
||||
memmove(kp->keyid, keyid, keylen);
|
||||
kp->keylen = keylen;
|
||||
}
|
||||
|
||||
for (strp = &str_keyid[4]; keylen > 0; --keylen) {
|
||||
if ((*strp++ = *keyid++) == IAC)
|
||||
*strp++ = IAC;
|
||||
}
|
||||
*strp++ = IAC;
|
||||
*strp++ = SE;
|
||||
telnet_net_write(str_keyid, strp - str_keyid);
|
||||
printsub('>', &str_keyid[2], strp - str_keyid - 2);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_auto(int on)
|
||||
{
|
||||
if (on < 0)
|
||||
autoencrypt ^= 1;
|
||||
else
|
||||
autoencrypt = on ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
decrypt_auto(int on)
|
||||
{
|
||||
if (on < 0)
|
||||
autodecrypt ^= 1;
|
||||
else
|
||||
autodecrypt = on ? 1 : 0;
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_start_output(int type)
|
||||
{
|
||||
Encryptions *ep;
|
||||
register unsigned char *p;
|
||||
register int i;
|
||||
|
||||
if (!(ep = findencryption(type))) {
|
||||
if (encrypt_debug_mode) {
|
||||
printf(">>>%s: Can't encrypt with type %s (%d)\r\n",
|
||||
Name,
|
||||
ENCTYPE_NAME_OK(type)
|
||||
? ENCTYPE_NAME(type) : "(unknown)",
|
||||
type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ep->start) {
|
||||
i = (*ep->start)(DIR_ENCRYPT, Server);
|
||||
if (encrypt_debug_mode) {
|
||||
printf(">>>%s: Encrypt start: %s (%d) %s\r\n",
|
||||
Name,
|
||||
(i < 0) ? "failed" :
|
||||
"initial negotiation in progress",
|
||||
i, ENCTYPE_NAME(type));
|
||||
}
|
||||
if (i)
|
||||
return;
|
||||
}
|
||||
p = str_start + 3;
|
||||
*p++ = ENCRYPT_START;
|
||||
for (i = 0; i < ki[0].keylen; ++i) {
|
||||
if ((*p++ = ki[0].keyid[i]) == IAC)
|
||||
*p++ = IAC;
|
||||
}
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
telnet_net_write(str_start, p - str_start);
|
||||
net_encrypt();
|
||||
printsub('>', &str_start[2], p - &str_start[2]);
|
||||
/*
|
||||
* If we are already encrypting in some mode, then
|
||||
* encrypt the ring (which includes our request) in
|
||||
* the old mode, mark it all as "clear text" and then
|
||||
* switch to the new mode.
|
||||
*/
|
||||
encrypt_output = ep->output;
|
||||
encrypt_mode = type;
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Started to encrypt output with type %s\r\n",
|
||||
Name, ENCTYPE_NAME(type));
|
||||
if (encrypt_verbose)
|
||||
printf("[ Output is now encrypted with type %s ]\r\n",
|
||||
ENCTYPE_NAME(type));
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_send_end(void)
|
||||
{
|
||||
if (!encrypt_output)
|
||||
return;
|
||||
|
||||
str_end[3] = ENCRYPT_END;
|
||||
telnet_net_write(str_end, sizeof(str_end));
|
||||
net_encrypt();
|
||||
printsub('>', &str_end[2], sizeof(str_end) - 2);
|
||||
/*
|
||||
* Encrypt the output buffer now because it will not be done by
|
||||
* netflush...
|
||||
*/
|
||||
encrypt_output = 0;
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Output is back to clear text\r\n", Name);
|
||||
if (encrypt_verbose)
|
||||
printf("[ Output is now clear text ]\r\n");
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_send_request_start(void)
|
||||
{
|
||||
register unsigned char *p;
|
||||
register int i;
|
||||
|
||||
p = &str_start[3];
|
||||
*p++ = ENCRYPT_REQSTART;
|
||||
for (i = 0; i < ki[1].keylen; ++i) {
|
||||
if ((*p++ = ki[1].keyid[i]) == IAC)
|
||||
*p++ = IAC;
|
||||
}
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
telnet_net_write(str_start, p - str_start);
|
||||
printsub('>', &str_start[2], p - &str_start[2]);
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Request input to be encrypted\r\n", Name);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_send_request_end(void)
|
||||
{
|
||||
str_end[3] = ENCRYPT_REQEND;
|
||||
telnet_net_write(str_end, sizeof(str_end));
|
||||
printsub('>', &str_end[2], sizeof(str_end) - 2);
|
||||
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: Request input to be clear text\r\n", Name);
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_wait(void)
|
||||
{
|
||||
if (encrypt_debug_mode)
|
||||
printf(">>>%s: in encrypt_wait\r\n", Name);
|
||||
if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt))
|
||||
return;
|
||||
while (autoencrypt && !encrypt_output)
|
||||
if (telnet_spin())
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_debug(int mode)
|
||||
{
|
||||
encrypt_debug_mode = mode;
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_gen_printsub(unsigned char *data, int cnt,
|
||||
unsigned char *buf, int buflen)
|
||||
{
|
||||
char tbuf[16], *cp;
|
||||
|
||||
cnt -= 2;
|
||||
data += 2;
|
||||
buf[buflen-1] = '\0';
|
||||
buf[buflen-2] = '*';
|
||||
buflen -= 2;
|
||||
for (; cnt > 0; cnt--, data++) {
|
||||
snprintf(tbuf, sizeof(tbuf), " %d", *data);
|
||||
for (cp = tbuf; *cp && buflen > 0; --buflen)
|
||||
*buf++ = *cp++;
|
||||
if (buflen <= 0)
|
||||
return;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_printsub(unsigned char *data, int cnt,
|
||||
unsigned char *buf, int buflen)
|
||||
{
|
||||
Encryptions *ep;
|
||||
register int type = data[1];
|
||||
|
||||
for (ep = encryptions; ep->type && ep->type != type; ep++)
|
||||
;
|
||||
|
||||
if (ep->printsub)
|
||||
(*ep->printsub)(data, cnt, buf, buflen);
|
||||
else
|
||||
encrypt_gen_printsub(data, cnt, buf, buflen);
|
||||
}
|
||||
#endif /* ENCRYPTION */
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/* $NetBSD: encrypt.h,v 1.9 2012/01/09 15:25:33 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)encrypt.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifdef ENCRYPTION
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
# ifndef __ENCRYPTION__
|
||||
# define __ENCRYPTION__
|
||||
|
||||
#define DIR_DECRYPT 1
|
||||
#define DIR_ENCRYPT 2
|
||||
|
||||
#define Block des_cblock
|
||||
typedef unsigned char *BlockT;
|
||||
#define Schedule des_key_schedule
|
||||
|
||||
#define VALIDKEY(key) ( key[0] | key[1] | key[2] | key[3] | \
|
||||
key[4] | key[5] | key[6] | key[7])
|
||||
|
||||
#define SAMEKEY(k1, k2) (!bcmp((void *)k1, (void *)k2, sizeof(Block)))
|
||||
|
||||
typedef struct {
|
||||
short type;
|
||||
int length;
|
||||
unsigned char *data;
|
||||
} Session_Key;
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int type;
|
||||
void (*output)(unsigned char *, int);
|
||||
int (*input)(int);
|
||||
void (*init)(int);
|
||||
int (*start)(int, int);
|
||||
int (*is)(unsigned char *, int);
|
||||
int (*reply)(unsigned char *, int);
|
||||
void (*session)(Session_Key *, int);
|
||||
int (*keyid)(int, unsigned char *, int *);
|
||||
void (*printsub)(unsigned char *, int, unsigned char *, int);
|
||||
} Encryptions;
|
||||
|
||||
#define SK_DES 1 /* Matched Kerberos v5 KEYTYPE_DES */
|
||||
|
||||
#include "enc-proto.h"
|
||||
|
||||
extern int encrypt_debug_mode;
|
||||
extern int (*decrypt_input)(int);
|
||||
extern void (*encrypt_output)(unsigned char *, int);
|
||||
# endif /* __ENCRYPTION__ */
|
||||
#endif /* ENCRYPTION */
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/* $NetBSD: genget.c,v 1.13 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)genget.c 8.2 (Berkeley) 5/30/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: genget.c,v 1.13 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include "misc.h"
|
||||
|
||||
#define LOWER(x) (isupper((unsigned char)x) ? tolower((unsigned char)x) : (x))
|
||||
/*
|
||||
* The prefix function returns 0 if *s1 is not a prefix
|
||||
* of *s2. If *s1 exactly matches *s2, the negative of
|
||||
* the length is returned. If *s1 is a prefix of *s2,
|
||||
* the length of *s1 is returned.
|
||||
*/
|
||||
int
|
||||
isprefix(char *s1, const char *s2)
|
||||
{
|
||||
char *os1;
|
||||
char c1, c2;
|
||||
|
||||
if (*s1 == '\0')
|
||||
return(-1);
|
||||
os1 = s1;
|
||||
c1 = *s1;
|
||||
c2 = *s2;
|
||||
while (LOWER(c1) == LOWER(c2)) {
|
||||
if (c1 == '\0')
|
||||
break;
|
||||
c1 = *++s1;
|
||||
c2 = *++s2;
|
||||
}
|
||||
return(*s1 ? 0 : (*s2 ? (s1 - os1) : (os1 - s1)));
|
||||
}
|
||||
|
||||
static char *ambiguous; /* special return value for command routines */
|
||||
|
||||
char **
|
||||
genget( char *name, /* name to match */
|
||||
char **table, /* name entry in table */
|
||||
int stlen)
|
||||
{
|
||||
register char **c, **found;
|
||||
register int n;
|
||||
|
||||
if (name == 0)
|
||||
return 0;
|
||||
|
||||
found = 0;
|
||||
for (c = table; *c != 0; c = (char **)((char *)c + stlen)) {
|
||||
if ((n = isprefix(name, *c)) == 0)
|
||||
continue;
|
||||
if (n < 0) /* exact match */
|
||||
return(c);
|
||||
if (found)
|
||||
return(&ambiguous);
|
||||
found = c;
|
||||
}
|
||||
return(found);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function call version of Ambiguous()
|
||||
*/
|
||||
int
|
||||
Ambiguous(void *s)
|
||||
{
|
||||
return(s == &ambiguous);
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
/* $NetBSD: getent.c,v 1.11 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)getent.c 8.2 (Berkeley) 12/15/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: getent.c,v 1.11 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "misc-proto.h"
|
||||
|
||||
static char *area;
|
||||
|
||||
int getent(char *, char *);
|
||||
char *getstr(char *, char **);
|
||||
|
||||
/*ARGSUSED*/
|
||||
int
|
||||
getent(char *cp, char *name)
|
||||
{
|
||||
#ifdef HAS_CGETENT
|
||||
const char *dba[2];
|
||||
|
||||
dba[0] = "/etc/gettytab";
|
||||
dba[1] = 0;
|
||||
return((cgetent(&area, dba, name) == 0) ? 1 : 0);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef SOLARIS
|
||||
/*ARGSUSED*/
|
||||
char *
|
||||
getstr(char *id, char **cpp)
|
||||
{
|
||||
# ifdef HAS_CGETENT
|
||||
char *answer;
|
||||
return((cgetstr(area, id, &answer) > 0) ? answer : 0);
|
||||
# else
|
||||
return(0);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,731 +0,0 @@
|
|||
/* $NetBSD: kerberos5.c,v 1.20 2014/04/26 22:10:40 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America may
|
||||
* require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifdef KRB5
|
||||
#include <arpa/telnet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <pwd.h>
|
||||
#define Authenticator k5_Authenticator
|
||||
#include <krb5.h>
|
||||
#undef Authenticator
|
||||
/* #include <roken.h> */
|
||||
|
||||
#include "encrypt.h"
|
||||
#include "auth.h"
|
||||
#include "misc.h"
|
||||
|
||||
extern int net;
|
||||
|
||||
int forward_flags; /* Flags get set in telnet/main.c on -f and -F */
|
||||
int got_forwarded_creds;/* Tell telnetd to pass -F or -f to login. */
|
||||
|
||||
int require_hwpreauth;
|
||||
|
||||
const char *get_krb5_err_text(krb5_context, krb5_error_code);
|
||||
void kerberos5_forward(Authenticator *);
|
||||
|
||||
static unsigned char str_data[1024] = {IAC, SB, TELOPT_AUTHENTICATION, 0,
|
||||
AUTHTYPE_KERBEROS_V5,};
|
||||
|
||||
#define KRB_AUTH 0 /* Authentication data follows */
|
||||
#define KRB_REJECT 1 /* Rejected (reason might follow) */
|
||||
#define KRB_ACCEPT 2 /* Accepted */
|
||||
#define KRB_RESPONSE 3 /* Response for mutual auth. */
|
||||
|
||||
#define KRB_FORWARD 4 /* Forwarded credentials follow */
|
||||
#define KRB_FORWARD_ACCEPT 5 /* Forwarded credentials accepted */
|
||||
#define KRB_FORWARD_REJECT 6 /* Forwarded credentials rejected */
|
||||
|
||||
static krb5_data auth;
|
||||
static krb5_ticket *ticket;
|
||||
|
||||
krb5_context telnet_context;
|
||||
static krb5_auth_context auth_context;
|
||||
|
||||
static int
|
||||
Data(Authenticator *ap, int type, const void *d, int c)
|
||||
{
|
||||
unsigned char *p = str_data + 4;
|
||||
const unsigned char *cd = (const unsigned char *) d;
|
||||
|
||||
if (c == -1)
|
||||
c = strlen(cd);
|
||||
|
||||
if (auth_debug_mode) {
|
||||
printf("%s:%d: [%d] (%d)",
|
||||
str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
|
||||
str_data[3],
|
||||
type, c);
|
||||
printd(d, c);
|
||||
printf("\r\n");
|
||||
}
|
||||
*p++ = ap->type;
|
||||
*p++ = ap->way;
|
||||
*p++ = type;
|
||||
while (c-- > 0) {
|
||||
if ((*p++ = *cd++) == IAC)
|
||||
*p++ = IAC;
|
||||
}
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
if (str_data[3] == TELQUAL_IS)
|
||||
printsub('>', &str_data[2], p - &str_data[2]);
|
||||
return (telnet_net_write(str_data, p - str_data));
|
||||
}
|
||||
|
||||
const char *
|
||||
get_krb5_err_text(krb5_context ctx, krb5_error_code ret)
|
||||
{
|
||||
static const char *str = NULL;
|
||||
|
||||
if (str)
|
||||
krb5_free_error_message(ctx, str);
|
||||
|
||||
str = krb5_get_error_message(ctx, ret);
|
||||
|
||||
if (str != NULL)
|
||||
return str;
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
int
|
||||
kerberos5_init(Authenticator *ap, int server)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
if (telnet_context == 0) {
|
||||
ret = krb5_init_context(&telnet_context);
|
||||
if (ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (server) {
|
||||
krb5_keytab kt;
|
||||
krb5_kt_cursor cursor;
|
||||
|
||||
ret = krb5_kt_default(telnet_context, &kt);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
ret = krb5_kt_start_seq_get(telnet_context, kt, &cursor);
|
||||
if (ret) {
|
||||
krb5_kt_close(telnet_context, kt);
|
||||
return 0;
|
||||
}
|
||||
krb5_kt_end_seq_get(telnet_context, kt, &cursor);
|
||||
krb5_kt_close(telnet_context, kt);
|
||||
|
||||
str_data[3] = TELQUAL_REPLY;
|
||||
} else
|
||||
str_data[3] = TELQUAL_IS;
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
kerberos5_send(Authenticator *ap)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_ccache ccache;
|
||||
int ap_opts;
|
||||
krb5_data cksum_data;
|
||||
char foo[2];
|
||||
|
||||
printf("[ Trying KERBEROS5 ... ]\r\n");
|
||||
|
||||
if (!UserNameRequested) {
|
||||
if (auth_debug_mode) {
|
||||
printf("Kerberos V5: no user name supplied\r\n");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
ret = krb5_cc_default(telnet_context, &ccache);
|
||||
if (ret) {
|
||||
if (auth_debug_mode) {
|
||||
printf(
|
||||
"Kerberos V5: could not get default ccache: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
|
||||
ap_opts = AP_OPTS_MUTUAL_REQUIRED;
|
||||
else
|
||||
ap_opts = 0;
|
||||
|
||||
ap_opts |= AP_OPTS_USE_SUBKEY;
|
||||
|
||||
ret = krb5_auth_con_init(telnet_context, &auth_context);
|
||||
if (ret) {
|
||||
if (auth_debug_mode) {
|
||||
printf(
|
||||
"Kerberos V5: krb5_auth_con_init failed: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
ret = krb5_auth_con_setaddrs_from_fd(telnet_context,
|
||||
auth_context, &net);
|
||||
if (ret) {
|
||||
if (auth_debug_mode) {
|
||||
printf("Kerberos V5: "
|
||||
"krb5_auth_con_setaddrs_from_fd failed: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
krb5_auth_con_setkeytype(telnet_context, auth_context,
|
||||
ETYPE_DES_CBC_CRC);
|
||||
|
||||
foo[0] = ap->type;
|
||||
foo[1] = ap->way;
|
||||
|
||||
cksum_data.length = sizeof(foo);
|
||||
cksum_data.data = foo;
|
||||
ret = krb5_mk_req(telnet_context, &auth_context, ap_opts, "host",
|
||||
RemoteHostName, &cksum_data, ccache, &auth);
|
||||
if (ret) {
|
||||
if (1 || auth_debug_mode) {
|
||||
printf("Kerberos V5: mk_req failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!auth_sendname((unsigned char *) UserNameRequested,
|
||||
strlen(UserNameRequested))) {
|
||||
if (auth_debug_mode)
|
||||
printf("Not enough room for user name\r\n");
|
||||
return (0);
|
||||
}
|
||||
if (!Data(ap, KRB_AUTH, auth.data, auth.length)) {
|
||||
if (auth_debug_mode)
|
||||
printf("Not enough room for authentication data\r\n");
|
||||
return (0);
|
||||
}
|
||||
if (auth_debug_mode) {
|
||||
printf("Sent Kerberos V5 credentials to server\r\n");
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
kerberos5_is(Authenticator * ap, unsigned char *data, int cnt)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_data outbuf;
|
||||
krb5_keyblock *key_block;
|
||||
char *name;
|
||||
krb5_principal server;
|
||||
int zero = 0;
|
||||
|
||||
if (cnt-- < 1)
|
||||
return;
|
||||
switch (*data++) {
|
||||
case KRB_AUTH:
|
||||
auth.data = (char *) data;
|
||||
auth.length = cnt;
|
||||
|
||||
auth_context = NULL;
|
||||
|
||||
ret = krb5_auth_con_init(telnet_context, &auth_context);
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
ret = krb5_auth_con_setaddrs_from_fd(telnet_context,
|
||||
auth_context, &zero);
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
ret = krb5_sock_to_principal(telnet_context, 0, "host",
|
||||
KRB5_NT_SRV_HST, &server);
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_sock_to_principal failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
ret = krb5_rd_req(telnet_context, &auth_context, &auth,
|
||||
server, NULL, NULL, &ticket);
|
||||
krb5_free_principal(telnet_context, server);
|
||||
|
||||
if (ret) {
|
||||
char *errbuf;
|
||||
|
||||
asprintf(&errbuf,
|
||||
"Read req failed: %s",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
Data(ap, KRB_REJECT, errbuf, -1);
|
||||
if (auth_debug_mode)
|
||||
printf("%s\r\n", errbuf);
|
||||
free(errbuf);
|
||||
return;
|
||||
} {
|
||||
char foo[2];
|
||||
|
||||
foo[0] = ap->type;
|
||||
foo[1] = ap->way;
|
||||
|
||||
ret = krb5_verify_authenticator_checksum(telnet_context,
|
||||
auth_context, foo, sizeof(foo));
|
||||
|
||||
if (ret) {
|
||||
char *errbuf;
|
||||
asprintf(&errbuf, "Bad checksum: %s",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
Data(ap, KRB_REJECT, errbuf, -1);
|
||||
if (auth_debug_mode)
|
||||
printf("%s\r\n", errbuf);
|
||||
free(errbuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ret = krb5_auth_con_getremotesubkey(telnet_context,
|
||||
auth_context, &key_block);
|
||||
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_auth_con_getremotesubkey failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
if (key_block == NULL) {
|
||||
ret = krb5_auth_con_getkey(telnet_context,
|
||||
auth_context,
|
||||
&key_block);
|
||||
}
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_auth_con_getkey failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
if (key_block == NULL) {
|
||||
Data(ap, KRB_REJECT, "no subkey received", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_auth_con_getremotesubkey returned NULL key\r\n");
|
||||
return;
|
||||
}
|
||||
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
|
||||
ret = krb5_mk_rep(telnet_context,
|
||||
auth_context, &outbuf);
|
||||
if (ret) {
|
||||
Data(ap, KRB_REJECT,
|
||||
"krb5_mk_rep failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: "
|
||||
"krb5_mk_rep failed (%s)\r\n",
|
||||
get_krb5_err_text(telnet_context,
|
||||
ret));
|
||||
krb5_free_keyblock(telnet_context, key_block);
|
||||
return;
|
||||
}
|
||||
Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
|
||||
}
|
||||
if (krb5_unparse_name(telnet_context, ticket->client, &name))
|
||||
name = 0;
|
||||
|
||||
if (UserNameRequested && krb5_kuserok(telnet_context,
|
||||
ticket->client, UserNameRequested)) {
|
||||
Data(ap, KRB_ACCEPT, name ? name : "", name ? -1 : 0);
|
||||
if (auth_debug_mode) {
|
||||
printf("Kerberos5 identifies him as ``%s''\r\n",
|
||||
name ? name : "");
|
||||
}
|
||||
if (key_block->keytype == ETYPE_DES_CBC_MD5 ||
|
||||
key_block->keytype == ETYPE_DES_CBC_MD4 ||
|
||||
key_block->keytype == ETYPE_DES_CBC_CRC) {
|
||||
Session_Key skey;
|
||||
|
||||
skey.type = SK_DES;
|
||||
skey.length = 8;
|
||||
skey.data = key_block->keyvalue.data;
|
||||
encrypt_session_key(&skey, 0);
|
||||
}
|
||||
} else {
|
||||
char *msg;
|
||||
|
||||
asprintf(&msg, "user `%s' is not authorized to "
|
||||
"login as `%s'",
|
||||
name ? name : "<unknown>",
|
||||
UserNameRequested ? UserNameRequested : "<nobody>");
|
||||
if (msg == NULL)
|
||||
Data(ap, KRB_REJECT, NULL, 0);
|
||||
else {
|
||||
Data(ap, KRB_REJECT, (void *) msg, -1);
|
||||
free(msg);
|
||||
}
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
krb5_free_keyblock(telnet_context, key_block);
|
||||
break;
|
||||
}
|
||||
auth_finished(ap, AUTH_USER);
|
||||
krb5_free_keyblock(telnet_context, key_block);
|
||||
break;
|
||||
case KRB_FORWARD:{
|
||||
struct passwd pws, *pwd;
|
||||
char pwbuf[1024];
|
||||
char ccname[1024]; /* XXX */
|
||||
krb5_data inbuf;
|
||||
krb5_ccache ccache;
|
||||
inbuf.data = (char *) data;
|
||||
inbuf.length = cnt;
|
||||
|
||||
if (getpwnam_r(UserNameRequested, &pws, pwbuf,
|
||||
sizeof(pwbuf), &pwd) != 0 || pwd == NULL)
|
||||
break;
|
||||
|
||||
snprintf(ccname, sizeof(ccname),
|
||||
"FILE:/tmp/krb5cc_%u", pwd->pw_uid);
|
||||
|
||||
ret = krb5_cc_resolve(telnet_context, ccname, &ccache);
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: could not get ccache: %s\r\n",
|
||||
get_krb5_err_text(telnet_context,
|
||||
ret));
|
||||
break;
|
||||
}
|
||||
ret = krb5_cc_initialize(telnet_context, ccache,
|
||||
ticket->client);
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: could not init ccache: %s\r\n",
|
||||
get_krb5_err_text(telnet_context,
|
||||
ret));
|
||||
break;
|
||||
}
|
||||
ret = krb5_rd_cred2(telnet_context, auth_context,
|
||||
ccache, &inbuf);
|
||||
if (ret) {
|
||||
char *errbuf;
|
||||
|
||||
asprintf(&errbuf,
|
||||
"Read forwarded creds failed: %s",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
if (errbuf == NULL)
|
||||
Data(ap, KRB_FORWARD_REJECT, NULL, 0);
|
||||
else
|
||||
Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
|
||||
if (auth_debug_mode)
|
||||
printf("Could not read forwarded credentials: %s\r\n",
|
||||
errbuf);
|
||||
free(errbuf);
|
||||
} else
|
||||
Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
|
||||
chown(ccname + 5, pwd->pw_uid, -1);
|
||||
if (auth_debug_mode)
|
||||
printf("Forwarded credentials obtained\r\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (auth_debug_mode)
|
||||
printf("Unknown Kerberos option %d\r\n", data[-1]);
|
||||
Data(ap, KRB_REJECT, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kerberos5_reply(Authenticator * ap, unsigned char *data, int cnt)
|
||||
{
|
||||
static int mutual_complete = 0;
|
||||
|
||||
if (cnt-- < 1)
|
||||
return;
|
||||
switch (*data++) {
|
||||
case KRB_REJECT:
|
||||
if (cnt > 0) {
|
||||
printf("[ Kerberos V5 refuses authentication because %.*s ]\r\n",
|
||||
cnt, data);
|
||||
} else
|
||||
printf("[ Kerberos V5 refuses authentication ]\r\n");
|
||||
auth_send_retry();
|
||||
return;
|
||||
case KRB_ACCEPT:{
|
||||
krb5_error_code ret;
|
||||
Session_Key skey;
|
||||
krb5_keyblock *keyblock;
|
||||
|
||||
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL &&
|
||||
!mutual_complete) {
|
||||
printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n");
|
||||
auth_send_retry();
|
||||
return;
|
||||
}
|
||||
if (cnt)
|
||||
printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data);
|
||||
else
|
||||
printf("[ Kerberos V5 accepts you ]\r\n");
|
||||
|
||||
ret = krb5_auth_con_getlocalsubkey(telnet_context,
|
||||
auth_context, &keyblock);
|
||||
if (ret)
|
||||
ret = krb5_auth_con_getkey(telnet_context,
|
||||
auth_context, &keyblock);
|
||||
if (ret) {
|
||||
printf("[ krb5_auth_con_getkey: %s ]\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
auth_send_retry();
|
||||
return;
|
||||
}
|
||||
skey.type = SK_DES;
|
||||
skey.length = 8;
|
||||
skey.data = keyblock->keyvalue.data;
|
||||
encrypt_session_key(&skey, 0);
|
||||
krb5_free_keyblock(telnet_context, keyblock);
|
||||
auth_finished(ap, AUTH_USER);
|
||||
if (forward_flags & OPTS_FORWARD_CREDS)
|
||||
kerberos5_forward(ap);
|
||||
break;
|
||||
}
|
||||
case KRB_RESPONSE:
|
||||
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
|
||||
/* the rest of the reply should contain a krb_ap_rep */
|
||||
krb5_ap_rep_enc_part *reply;
|
||||
krb5_data inbuf;
|
||||
krb5_error_code ret;
|
||||
|
||||
inbuf.length = cnt;
|
||||
inbuf.data = (char *) data;
|
||||
|
||||
ret = krb5_rd_rep(telnet_context,
|
||||
auth_context, &inbuf, &reply);
|
||||
if (ret) {
|
||||
printf("[ Mutual authentication failed: %s ]\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
auth_send_retry();
|
||||
return;
|
||||
}
|
||||
krb5_free_ap_rep_enc_part(telnet_context, reply);
|
||||
mutual_complete = 1;
|
||||
}
|
||||
return;
|
||||
case KRB_FORWARD_ACCEPT:
|
||||
printf("[ Kerberos V5 accepted forwarded credentials ]\r\n");
|
||||
return;
|
||||
case KRB_FORWARD_REJECT:
|
||||
printf("[ Kerberos V5 refuses forwarded credentials because %.*s ]\r\n",
|
||||
cnt, data);
|
||||
return;
|
||||
default:
|
||||
if (auth_debug_mode)
|
||||
printf("Unknown Kerberos option %d\r\n", data[-1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
kerberos5_status(Authenticator *ap, char *name, size_t l, int level)
|
||||
{
|
||||
if (level < AUTH_USER)
|
||||
return (level);
|
||||
|
||||
if (UserNameRequested &&
|
||||
krb5_kuserok(telnet_context, ticket->client, UserNameRequested)) {
|
||||
strlcpy(name, UserNameRequested, l);
|
||||
return (AUTH_VALID);
|
||||
} else
|
||||
return (AUTH_USER);
|
||||
}
|
||||
#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
|
||||
#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
|
||||
|
||||
void
|
||||
kerberos5_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
|
||||
buf[buflen - 1] = '\0'; /* make sure its NULL terminated */
|
||||
buflen -= 1;
|
||||
|
||||
switch (data[3]) {
|
||||
case KRB_REJECT: /* Rejected (reason might follow) */
|
||||
strlcpy((char *) buf, " REJECT ", buflen);
|
||||
goto common;
|
||||
|
||||
case KRB_ACCEPT: /* Accepted (name might follow) */
|
||||
strlcpy((char *) buf, " ACCEPT ", buflen);
|
||||
common:
|
||||
BUMP(buf, buflen);
|
||||
if (cnt <= 4)
|
||||
break;
|
||||
ADDC(buf, buflen, '"');
|
||||
for (i = 4; i < cnt; i++)
|
||||
ADDC(buf, buflen, data[i]);
|
||||
ADDC(buf, buflen, '"');
|
||||
ADDC(buf, buflen, '\0');
|
||||
break;
|
||||
|
||||
|
||||
case KRB_AUTH: /* Authentication data follows */
|
||||
strlcpy((char *) buf, " AUTH", buflen);
|
||||
goto common2;
|
||||
|
||||
case KRB_RESPONSE:
|
||||
strlcpy((char *) buf, " RESPONSE", buflen);
|
||||
goto common2;
|
||||
|
||||
case KRB_FORWARD: /* Forwarded credentials follow */
|
||||
strlcpy((char *) buf, " FORWARD", buflen);
|
||||
goto common2;
|
||||
|
||||
case KRB_FORWARD_ACCEPT: /* Forwarded credentials accepted */
|
||||
strlcpy((char *) buf, " FORWARD_ACCEPT", buflen);
|
||||
goto common2;
|
||||
|
||||
case KRB_FORWARD_REJECT: /* Forwarded credentials rejected */
|
||||
/* (reason might follow) */
|
||||
strlcpy((char *) buf, " FORWARD_REJECT", buflen);
|
||||
goto common2;
|
||||
|
||||
default:
|
||||
snprintf(buf, buflen, " %d (unknown)", data[3]);
|
||||
common2:
|
||||
BUMP(buf, buflen);
|
||||
for (i = 4; i < cnt; i++) {
|
||||
snprintf(buf, buflen, " %d", data[i]);
|
||||
BUMP(buf, buflen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kerberos5_forward(Authenticator * ap)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_ccache ccache;
|
||||
krb5_creds creds;
|
||||
krb5_kdc_flags flags;
|
||||
krb5_data out_data;
|
||||
krb5_principal principal;
|
||||
|
||||
ret = krb5_cc_default(telnet_context, &ccache);
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("KerberosV5: could not get default ccache: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
ret = krb5_cc_get_principal(telnet_context, ccache, &principal);
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("KerberosV5: could not get principal: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
memset(&creds, 0, sizeof(creds));
|
||||
|
||||
creds.client = principal;
|
||||
|
||||
ret = krb5_build_principal(telnet_context, &creds.server,
|
||||
strlen(principal->realm), principal->realm, "krbtgt",
|
||||
principal->realm, NULL);
|
||||
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("KerberosV5: could not get principal: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
creds.times.endtime = 0;
|
||||
|
||||
flags.i = 0;
|
||||
flags.b.forwarded = 1;
|
||||
if (forward_flags & OPTS_FORWARDABLE_CREDS)
|
||||
flags.b.forwardable = 1;
|
||||
|
||||
ret = krb5_get_forwarded_creds(telnet_context, auth_context,
|
||||
ccache, flags.i, RemoteHostName, &creds, &out_data);
|
||||
if (ret) {
|
||||
if (auth_debug_mode)
|
||||
printf("Kerberos V5: error getting forwarded creds: %s\r\n",
|
||||
get_krb5_err_text(telnet_context, ret));
|
||||
return;
|
||||
}
|
||||
if (!Data(ap, KRB_FORWARD, out_data.data, out_data.length)) {
|
||||
if (auth_debug_mode)
|
||||
printf("Not enough room for authentication data\r\n");
|
||||
} else {
|
||||
if (auth_debug_mode)
|
||||
printf("Forwarded local Kerberos V5 credentials to server\r\n");
|
||||
}
|
||||
}
|
||||
#endif /* KRB5 */
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/* $NetBSD: key-proto.h,v 1.6 2005/02/06 05:53:07 perry Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)key-proto.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef __KEY_PROTO__
|
||||
#define __KEY_PROTO__
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
int key_file_exists(void);
|
||||
void key_lookup(unsigned char *, Block);
|
||||
void key_stream_init(Block, Block, int);
|
||||
unsigned char key_stream(int, int);
|
||||
#endif
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/* $NetBSD: misc-proto.h,v 1.10 2005/02/06 05:53:07 perry Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)misc-proto.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1990 by the Massachusetts Institute of Technology
|
||||
*
|
||||
* Export of this software from the United States of America is assumed
|
||||
* to require a specific license from the United States Government.
|
||||
* It is the responsibility of any person or organization contemplating
|
||||
* export to obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of M.I.T. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*/
|
||||
|
||||
#ifndef __MISC_PROTO__
|
||||
#define __MISC_PROTO__
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
void auth_encrypt_init(const char *, const char *, const char *, int);
|
||||
void auth_encrypt_user(const char *);
|
||||
void auth_encrypt_connect(int);
|
||||
void printd(const unsigned char *, int);
|
||||
|
||||
/*
|
||||
* These functions are imported from the application
|
||||
*/
|
||||
int telnet_net_write(unsigned char *, int);
|
||||
void net_encrypt(void);
|
||||
int telnet_spin(void);
|
||||
char *telnet_getenv(char *);
|
||||
char *telnet_gets(char *, char *, int, int);
|
||||
#endif
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
/* $NetBSD: misc.c,v 1.13 2012/03/21 05:33:27 matt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/4/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: misc.c,v 1.13 2012/03/21 05:33:27 matt Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "misc.h"
|
||||
#include "auth.h"
|
||||
#include "encrypt.h"
|
||||
|
||||
const char *RemoteHostName;
|
||||
const char *LocalHostName;
|
||||
char *UserNameRequested = 0;
|
||||
int ConnectedCount = 0;
|
||||
|
||||
void
|
||||
auth_encrypt_init(const char *local, const char *remote, const char *name,
|
||||
int server)
|
||||
{
|
||||
RemoteHostName = remote;
|
||||
LocalHostName = local;
|
||||
#ifdef AUTHENTICATION
|
||||
auth_init(name, server);
|
||||
#endif
|
||||
#ifdef ENCRYPTION
|
||||
encrypt_init(name, server);
|
||||
#endif /* ENCRYPTION */
|
||||
if (UserNameRequested) {
|
||||
free(UserNameRequested);
|
||||
UserNameRequested = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
auth_encrypt_user(const char *name)
|
||||
{
|
||||
if (UserNameRequested)
|
||||
free(UserNameRequested);
|
||||
UserNameRequested = name ? strdup(name) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
auth_encrypt_connect(int cnt)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
printd(const unsigned char *data, int cnt)
|
||||
{
|
||||
if (cnt > 16)
|
||||
cnt = 16;
|
||||
while (cnt-- > 0) {
|
||||
printf(" %02x", *data);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/* $NetBSD: misc.h,v 1.9 2012/01/09 15:25:34 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)misc.h 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
__BEGIN_DECLS
|
||||
extern char *UserNameRequested;
|
||||
extern const char *LocalHostName;
|
||||
extern const char *RemoteHostName;
|
||||
extern int ConnectedCount;
|
||||
extern int ReservedPort;
|
||||
|
||||
int isprefix(char *, const char *);
|
||||
char **genget(char *, char **, int);
|
||||
int Ambiguous(void *);
|
||||
__END_DECLS
|
||||
|
||||
#include "misc-proto.h"
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
* Dave Safford. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifdef notdef
|
||||
__FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/pk.c,v 1.10 2002/08/22 06:19:07 nsayer Exp $");
|
||||
#else
|
||||
__RCSID("$NetBSD: pk.c,v 1.4 2005/02/19 22:55:35 christos Exp $");
|
||||
#endif
|
||||
|
||||
/* public key routines */
|
||||
/* functions:
|
||||
genkeys(char *public, char *secret)
|
||||
common_key(char *secret, char *public, desData *deskey)
|
||||
pk_encode(char *in, *out, DesData *deskey);
|
||||
pk_decode(char *in, *out, DesData *deskey);
|
||||
where
|
||||
char public[HEXKEYBYTES + 1];
|
||||
char secret[HEXKEYBYTES + 1];
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <des.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pk.h"
|
||||
|
||||
static void adjust(char *, const char *);
|
||||
|
||||
/*
|
||||
* Choose top 128 bits of the common key to use as our idea key.
|
||||
*/
|
||||
static void
|
||||
extractideakey(BIGNUM *ck, IdeaData *ideakey)
|
||||
{
|
||||
BIGNUM *a = BN_new();
|
||||
BIGNUM *z = BN_new();
|
||||
BIGNUM *base = BN_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
size_t i;
|
||||
char *k;
|
||||
|
||||
(void)BN_zero(a);
|
||||
(void)BN_zero(z);
|
||||
(void)BN_set_word(base, 1 << 8);
|
||||
BN_add(a, ck, z);
|
||||
|
||||
for (i = 0; i < ((KEYSIZE - 128) / 8); i++)
|
||||
BN_div(a, z, a, base, ctx);
|
||||
|
||||
k = (char *)(void *)ideakey;
|
||||
for (i = 0; i < 16; i++) {
|
||||
BN_div(a, z, a, base, ctx);
|
||||
*k++ = (char)BN_get_word(z);
|
||||
}
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(base);
|
||||
BN_free(z);
|
||||
BN_free(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose middle 64 bits of the common key to use as our des key, possibly
|
||||
* overwriting the lower order bits by setting parity.
|
||||
*/
|
||||
static void
|
||||
extractdeskey(BIGNUM *ck, DesData *deskey)
|
||||
{
|
||||
BIGNUM *a = BN_new();
|
||||
BIGNUM *z = BN_new();
|
||||
BIGNUM *base = BN_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
size_t i;
|
||||
char *k;
|
||||
|
||||
(void)BN_zero(z);
|
||||
(void)BN_zero(a);
|
||||
(void)BN_set_word(base, 1 << 8);
|
||||
BN_add(a, ck, z);
|
||||
|
||||
for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++)
|
||||
BN_div(a, z, a, base, ctx);
|
||||
|
||||
k = (char *)deskey;
|
||||
for (i = 0; i < 8; i++) {
|
||||
BN_div(a, z, a, base, ctx);
|
||||
*k++ = (char)BN_get_word(z);
|
||||
}
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(base);
|
||||
BN_free(z);
|
||||
BN_free(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* get common key from my secret key and his public key
|
||||
*/
|
||||
void
|
||||
common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
|
||||
{
|
||||
BIGNUM *public = BN_new();
|
||||
BIGNUM *secret = BN_new();
|
||||
BIGNUM *common = BN_new();
|
||||
BIGNUM *modulus = BN_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
|
||||
(void)BN_hex2bn(&modulus, HEXMODULUS);
|
||||
(void)BN_hex2bn(&public, xpublic);
|
||||
(void)BN_hex2bn(&secret, xsecret);
|
||||
(void)BN_zero(common);
|
||||
|
||||
BN_mod_exp(common, public, secret, modulus, ctx);
|
||||
extractdeskey(common, deskey);
|
||||
extractideakey(common, ideakey);
|
||||
des_set_odd_parity(deskey);
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(common);
|
||||
BN_free(secret);
|
||||
BN_free(public);
|
||||
BN_free(modulus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a seed
|
||||
*/
|
||||
static void
|
||||
getseed(char *seed, size_t seedsize)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < seedsize; i++)
|
||||
seed[i] = arc4random() & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a random public/secret key pair
|
||||
*/
|
||||
void
|
||||
genkeys(char *public, char *secret)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
# define BASEBITS (8 * sizeof(short) - 1)
|
||||
# define BASE (1 << BASEBITS)
|
||||
|
||||
BIGNUM *pk = BN_new();
|
||||
BIGNUM *sk = BN_new();
|
||||
BIGNUM *tmp = BN_new();
|
||||
BIGNUM *base = BN_new();
|
||||
BIGNUM *root = BN_new();
|
||||
BIGNUM *modulus = BN_new();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
short r;
|
||||
unsigned short seed[KEYSIZE/BASEBITS + 1];
|
||||
char *xkey;
|
||||
|
||||
(void)BN_zero(pk);
|
||||
(void)BN_zero(sk);
|
||||
(void)BN_set_word(base, BASE);
|
||||
(void)BN_set_word(root, PROOT);
|
||||
(void)BN_hex2bn(&modulus, HEXMODULUS);
|
||||
|
||||
getseed((char *)seed, sizeof(seed));
|
||||
for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
|
||||
r = seed[i] % BASE;
|
||||
(void)BN_set_word(tmp, r);
|
||||
BN_mul(sk, tmp, sk, ctx);
|
||||
BN_add(sk, tmp, sk);
|
||||
}
|
||||
|
||||
(void)BN_zero(tmp);
|
||||
BN_div(tmp, sk, sk, modulus, ctx);
|
||||
BN_mod_exp(pk, root, sk, modulus, ctx);
|
||||
|
||||
xkey = BN_bn2hex(sk);
|
||||
adjust(secret, xkey);
|
||||
xkey = BN_bn2hex(pk);
|
||||
adjust(public, xkey);
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(sk);
|
||||
BN_free(base);
|
||||
BN_free(pk);
|
||||
BN_free(tmp);
|
||||
BN_free(root);
|
||||
BN_free(modulus);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the input key so that it is 0-filled on the left
|
||||
*/
|
||||
static void
|
||||
adjust(char *keyout, const char *keyin)
|
||||
{
|
||||
const char *p;
|
||||
char *s;
|
||||
|
||||
for (p = keyin; *p; p++)
|
||||
continue;
|
||||
for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--)
|
||||
*s = *p;
|
||||
while (s >= keyout)
|
||||
*s-- = '0';
|
||||
}
|
||||
|
||||
static const char hextab[] = "0123456789ABCDEF";
|
||||
|
||||
/* given a DES key, cbc encrypt and translate input to terminated hex */
|
||||
void
|
||||
pk_encode(const char *in, char *out, DesData *key)
|
||||
{
|
||||
char buf[256];
|
||||
DesData i;
|
||||
des_key_schedule k;
|
||||
size_t l, op, deslen;
|
||||
|
||||
(void)memset(&i, 0, sizeof(i));
|
||||
(void)memset(buf, 0, sizeof(buf));
|
||||
deslen = ((strlen(in) + 7) / 8) * 8;
|
||||
des_key_sched(key, k);
|
||||
des_cbc_encrypt(in, buf, deslen, k, &i, DES_ENCRYPT);
|
||||
for (l = 0, op = 0; l < deslen; l++) {
|
||||
out[op++] = hextab[(buf[l] & 0xf0) >> 4];
|
||||
out[op++] = hextab[(buf[l] & 0x0f)];
|
||||
}
|
||||
out[op] = '\0';
|
||||
}
|
||||
|
||||
/* given a DES key, translate input from hex and decrypt */
|
||||
void
|
||||
pk_decode(const char *in, char *out, DesData *key)
|
||||
{
|
||||
char buf[256];
|
||||
DesData i;
|
||||
des_key_schedule k;
|
||||
int n1, n2, op;
|
||||
size_t l;
|
||||
size_t len = strlen(in) / 2;
|
||||
|
||||
(void)memset(&i, 0, sizeof(i));
|
||||
(void)memset(buf, 0, sizeof(buf));
|
||||
|
||||
for (l = 0, op = 0; l < len; l++, op += 2) {
|
||||
if (in[op] > '9')
|
||||
n1 = in[op] - 'A' + 10;
|
||||
else
|
||||
n1 = in[op] - '0';
|
||||
if (in[op + 1] > '9')
|
||||
n2 = in[op + 1] - 'A' + 10;
|
||||
else
|
||||
n2 = in[op + 1] - '0';
|
||||
buf[l] = (char)(n1 * 16 + n2);
|
||||
}
|
||||
des_key_sched(key, k);
|
||||
des_cbc_encrypt(buf, out, len, k, &i, DES_DECRYPT);
|
||||
out[len] = '\0';
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# $NetBSD: shlib_version,v 1.11 2009/01/11 03:07:50 christos Exp $
|
||||
# Remember to update distrib/sets/lists/base/shl.* when changing
|
||||
#
|
||||
major=7
|
||||
minor=0
|
||||
|
|
@ -1,594 +0,0 @@
|
|||
/* $NetBSD: spx.c,v 1.7 2005/04/19 03:19:46 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)spx.c 8.2 (Berkeley) 5/30/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: spx.c,v 1.7 2005/04/19 03:19:46 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#ifdef SPX
|
||||
/*
|
||||
* COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
|
||||
* ALL RIGHTS RESERVED
|
||||
*
|
||||
* "Digital Equipment Corporation authorizes the reproduction,
|
||||
* distribution and modification of this software subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* 1. Any partial or whole copy of this software, or any modification
|
||||
* thereof, must include this copyright notice in its entirety.
|
||||
*
|
||||
* 2. This software is supplied "as is" with no warranty of any kind,
|
||||
* expressed or implied, for any purpose, including any warranty of fitness
|
||||
* or merchantibility. DIGITAL assumes no responsibility for the use or
|
||||
* reliability of this software, nor promises to provide any form of
|
||||
* support for it on any basis.
|
||||
*
|
||||
* 3. Distribution of this software is authorized only if no profit or
|
||||
* remuneration of any kind is received in exchange for such distribution.
|
||||
*
|
||||
* 4. This software produces public key authentication certificates
|
||||
* bearing an expiration date established by DIGITAL and RSA Data
|
||||
* Security, Inc. It may cease to generate certificates after the expiration
|
||||
* date. Any modification of this software that changes or defeats
|
||||
* the expiration date or its effect is unauthorized.
|
||||
*
|
||||
* 5. Software that will renew or extend the expiration date of
|
||||
* authentication certificates produced by this software may be obtained
|
||||
* from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
|
||||
* 94065, (415)595-8782, or from DIGITAL"
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <arpa/telnet.h>
|
||||
#include <stdio.h>
|
||||
#include "gssapi_defs.h"
|
||||
#include <stdlib.h>
|
||||
#ifdef NO_STRING_H
|
||||
#include <strings.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
#include "encrypt.h"
|
||||
#include "auth.h"
|
||||
#include "misc.h"
|
||||
|
||||
extern auth_debug_mode;
|
||||
|
||||
static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
|
||||
AUTHTYPE_SPX, };
|
||||
static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
|
||||
TELQUAL_NAME, };
|
||||
|
||||
#define SPX_AUTH 0 /* Authentication data follows */
|
||||
#define SPX_REJECT 1 /* Rejected (reason might follow) */
|
||||
#define SPX_ACCEPT 2 /* Accepted */
|
||||
|
||||
#ifdef ENCRYPTION
|
||||
static Block session_key = { 0 };
|
||||
#endif /* ENCRYPTION */
|
||||
static Schedule sched;
|
||||
static Block challenge = { 0 };
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
gss_OID_set actual_mechs;
|
||||
gss_OID actual_mech_type, output_name_type;
|
||||
int major_status, status, msg_ctx = 0, new_status;
|
||||
int req_flags = 0, ret_flags, lifetime_rec;
|
||||
gss_cred_id_t gss_cred_handle;
|
||||
gss_ctx_id_t actual_ctxhandle, context_handle;
|
||||
gss_buffer_desc output_token, input_token, input_name_buffer;
|
||||
gss_buffer_desc status_string;
|
||||
gss_name_t desired_targname, src_name;
|
||||
gss_channel_bindings input_chan_bindings;
|
||||
char lhostname[GSS_C_MAX_PRINTABLE_NAME];
|
||||
char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
|
||||
int to_addr=0, from_addr=0;
|
||||
char *address;
|
||||
gss_buffer_desc fullname_buffer;
|
||||
gss_OID fullname_type;
|
||||
gss_cred_id_t gss_delegated_cred_handle;
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
|
||||
static int
|
||||
Data(ap, type, d, c)
|
||||
Authenticator *ap;
|
||||
int type;
|
||||
void *d;
|
||||
int c;
|
||||
{
|
||||
unsigned char *p = str_data + 4;
|
||||
unsigned char *cd = (unsigned char *)d;
|
||||
|
||||
if (c == -1)
|
||||
c = strlen((char *)cd);
|
||||
|
||||
if (0) {
|
||||
printf("%s:%d: [%d] (%d)",
|
||||
str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
|
||||
str_data[3],
|
||||
type, c);
|
||||
printd(d, c);
|
||||
printf("\r\n");
|
||||
}
|
||||
*p++ = ap->type;
|
||||
*p++ = ap->way;
|
||||
*p++ = type;
|
||||
while (c-- > 0) {
|
||||
if ((*p++ = *cd++) == IAC)
|
||||
*p++ = IAC;
|
||||
}
|
||||
*p++ = IAC;
|
||||
*p++ = SE;
|
||||
if (str_data[3] == TELQUAL_IS)
|
||||
printsub('>', &str_data[2], p - (&str_data[2]));
|
||||
return(telnet_net_write(str_data, p - str_data));
|
||||
}
|
||||
|
||||
int
|
||||
spx_init(ap, server)
|
||||
Authenticator *ap;
|
||||
int server;
|
||||
{
|
||||
gss_cred_id_t tmp_cred_handle;
|
||||
|
||||
if (server) {
|
||||
str_data[3] = TELQUAL_REPLY;
|
||||
gethostname(lhostname, sizeof(lhostname));
|
||||
strlcpy(targ_printable, "SERVICE:rcmd@",
|
||||
sizeof(targ_printable));
|
||||
strlcat(targ_printable, lhostname, sizeof(targ_printable));
|
||||
input_name_buffer.length = strlen(targ_printable);
|
||||
input_name_buffer.value = targ_printable;
|
||||
major_status = gss_import_name(&status,
|
||||
&input_name_buffer,
|
||||
GSS_C_NULL_OID,
|
||||
&desired_targname);
|
||||
major_status = gss_acquire_cred(&status,
|
||||
desired_targname,
|
||||
0,
|
||||
GSS_C_NULL_OID_SET,
|
||||
GSS_C_ACCEPT,
|
||||
&tmp_cred_handle,
|
||||
&actual_mechs,
|
||||
&lifetime_rec);
|
||||
if (major_status != GSS_S_COMPLETE) return(0);
|
||||
} else {
|
||||
str_data[3] = TELQUAL_IS;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
int
|
||||
spx_send(ap)
|
||||
Authenticator *ap;
|
||||
{
|
||||
Block enckey;
|
||||
int r;
|
||||
|
||||
gss_OID actual_mech_type, output_name_type;
|
||||
int msg_ctx = 0, new_status, status;
|
||||
int req_flags = 0, ret_flags, lifetime_rec, major_status;
|
||||
gss_buffer_desc output_token, input_token, input_name_buffer;
|
||||
gss_buffer_desc output_name_buffer, status_string;
|
||||
gss_name_t desired_targname;
|
||||
gss_channel_bindings input_chan_bindings;
|
||||
char targ_printable[GSS_C_MAX_PRINTABLE_NAME];
|
||||
int from_addr=0, to_addr=0, myhostlen, j;
|
||||
int deleg_flag=1, mutual_flag=0, replay_flag=0, seq_flag=0;
|
||||
char *address;
|
||||
|
||||
printf("[ Trying SPX ... ]\n");
|
||||
strlcpy(targ_printable, "SERVICE:rcmd@", sizeof(targ_printable));
|
||||
strlcat(targ_printable, RemoteHostName, sizeof(targ_printable));
|
||||
|
||||
input_name_buffer.length = strlen(targ_printable);
|
||||
input_name_buffer.value = targ_printable;
|
||||
|
||||
if (!UserNameRequested) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
major_status = gss_import_name(&status,
|
||||
&input_name_buffer,
|
||||
GSS_C_NULL_OID,
|
||||
&desired_targname);
|
||||
|
||||
|
||||
major_status = gss_display_name(&status,
|
||||
desired_targname,
|
||||
&output_name_buffer,
|
||||
&output_name_type);
|
||||
|
||||
printf("target is '%s'\n", output_name_buffer.value); fflush(stdout);
|
||||
|
||||
major_status = gss_release_buffer(&status, &output_name_buffer);
|
||||
|
||||
input_chan_bindings = (gss_channel_bindings)
|
||||
malloc(sizeof(gss_channel_bindings_desc));
|
||||
|
||||
input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
|
||||
input_chan_bindings->initiator_address.length = 4;
|
||||
address = (char *) malloc(4);
|
||||
input_chan_bindings->initiator_address.value = (char *) address;
|
||||
address[0] = ((from_addr & 0xff000000) >> 24);
|
||||
address[1] = ((from_addr & 0xff0000) >> 16);
|
||||
address[2] = ((from_addr & 0xff00) >> 8);
|
||||
address[3] = (from_addr & 0xff);
|
||||
input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
|
||||
input_chan_bindings->acceptor_address.length = 4;
|
||||
address = (char *) malloc(4);
|
||||
input_chan_bindings->acceptor_address.value = (char *) address;
|
||||
address[0] = ((to_addr & 0xff000000) >> 24);
|
||||
address[1] = ((to_addr & 0xff0000) >> 16);
|
||||
address[2] = ((to_addr & 0xff00) >> 8);
|
||||
address[3] = (to_addr & 0xff);
|
||||
input_chan_bindings->application_data.length = 0;
|
||||
|
||||
req_flags = 0;
|
||||
if (deleg_flag) req_flags = req_flags | 1;
|
||||
if (mutual_flag) req_flags = req_flags | 2;
|
||||
if (replay_flag) req_flags = req_flags | 4;
|
||||
if (seq_flag) req_flags = req_flags | 8;
|
||||
|
||||
major_status = gss_init_sec_context(&status, /* minor status */
|
||||
GSS_C_NO_CREDENTIAL, /* cred handle */
|
||||
&actual_ctxhandle, /* ctx handle */
|
||||
desired_targname, /* target name */
|
||||
GSS_C_NULL_OID, /* mech type */
|
||||
req_flags, /* req flags */
|
||||
0, /* time req */
|
||||
input_chan_bindings, /* chan binding */
|
||||
GSS_C_NO_BUFFER, /* input token */
|
||||
&actual_mech_type, /* actual mech */
|
||||
&output_token, /* output token */
|
||||
&ret_flags, /* ret flags */
|
||||
&lifetime_rec); /* time rec */
|
||||
|
||||
if ((major_status != GSS_S_COMPLETE) &&
|
||||
(major_status != GSS_S_CONTINUE_NEEDED)) {
|
||||
gss_display_status(&new_status,
|
||||
status,
|
||||
GSS_C_MECH_CODE,
|
||||
GSS_C_NULL_OID,
|
||||
&msg_ctx,
|
||||
&status_string);
|
||||
printf("%s\n", status_string.value);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (!Data(ap, SPX_AUTH, (void *)output_token.value, output_token.length)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
void
|
||||
spx_is(ap, data, cnt)
|
||||
Authenticator *ap;
|
||||
unsigned char *data;
|
||||
int cnt;
|
||||
{
|
||||
Session_Key skey;
|
||||
Block datablock;
|
||||
int r;
|
||||
|
||||
if (cnt-- < 1)
|
||||
return;
|
||||
switch (*data++) {
|
||||
case SPX_AUTH:
|
||||
input_token.length = cnt;
|
||||
input_token.value = (char *) data;
|
||||
|
||||
gethostname(lhostname, sizeof(lhostname));
|
||||
|
||||
strlcpy(targ_printable, "SERVICE:rcmd@",
|
||||
sizeof(targ_printable));
|
||||
strlcat(targ_printable, lhostname, sizeof(targ_printable));
|
||||
|
||||
input_name_buffer.length = strlen(targ_printable);
|
||||
input_name_buffer.value = targ_printable;
|
||||
|
||||
major_status = gss_import_name(&status,
|
||||
&input_name_buffer,
|
||||
GSS_C_NULL_OID,
|
||||
&desired_targname);
|
||||
|
||||
major_status = gss_acquire_cred(&status,
|
||||
desired_targname,
|
||||
0,
|
||||
GSS_C_NULL_OID_SET,
|
||||
GSS_C_ACCEPT,
|
||||
&gss_cred_handle,
|
||||
&actual_mechs,
|
||||
&lifetime_rec);
|
||||
|
||||
major_status = gss_release_name(&status, desired_targname);
|
||||
|
||||
input_chan_bindings = (gss_channel_bindings)
|
||||
malloc(sizeof(gss_channel_bindings_desc));
|
||||
|
||||
input_chan_bindings->initiator_addrtype = GSS_C_AF_INET;
|
||||
input_chan_bindings->initiator_address.length = 4;
|
||||
address = (char *) malloc(4);
|
||||
input_chan_bindings->initiator_address.value = (char *) address;
|
||||
address[0] = ((from_addr & 0xff000000) >> 24);
|
||||
address[1] = ((from_addr & 0xff0000) >> 16);
|
||||
address[2] = ((from_addr & 0xff00) >> 8);
|
||||
address[3] = (from_addr & 0xff);
|
||||
input_chan_bindings->acceptor_addrtype = GSS_C_AF_INET;
|
||||
input_chan_bindings->acceptor_address.length = 4;
|
||||
address = (char *) malloc(4);
|
||||
input_chan_bindings->acceptor_address.value = (char *) address;
|
||||
address[0] = ((to_addr & 0xff000000) >> 24);
|
||||
address[1] = ((to_addr & 0xff0000) >> 16);
|
||||
address[2] = ((to_addr & 0xff00) >> 8);
|
||||
address[3] = (to_addr & 0xff);
|
||||
input_chan_bindings->application_data.length = 0;
|
||||
|
||||
major_status = gss_accept_sec_context(&status,
|
||||
&context_handle,
|
||||
gss_cred_handle,
|
||||
&input_token,
|
||||
input_chan_bindings,
|
||||
&src_name,
|
||||
&actual_mech_type,
|
||||
&output_token,
|
||||
&ret_flags,
|
||||
&lifetime_rec,
|
||||
&gss_delegated_cred_handle);
|
||||
|
||||
|
||||
if (major_status != GSS_S_COMPLETE) {
|
||||
|
||||
major_status = gss_display_name(&status,
|
||||
src_name,
|
||||
&fullname_buffer,
|
||||
&fullname_type);
|
||||
Data(ap, SPX_REJECT, (void *)"auth failed", -1);
|
||||
auth_finished(ap, AUTH_REJECT);
|
||||
return;
|
||||
}
|
||||
|
||||
major_status = gss_display_name(&status,
|
||||
src_name,
|
||||
&fullname_buffer,
|
||||
&fullname_type);
|
||||
|
||||
|
||||
Data(ap, SPX_ACCEPT, (void *)output_token.value, output_token.length);
|
||||
auth_finished(ap, AUTH_USER);
|
||||
break;
|
||||
|
||||
default:
|
||||
Data(ap, SPX_REJECT, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
spx_reply(ap, data, cnt)
|
||||
Authenticator *ap;
|
||||
unsigned char *data;
|
||||
int cnt;
|
||||
{
|
||||
Session_Key skey;
|
||||
|
||||
if (cnt-- < 1)
|
||||
return;
|
||||
switch (*data++) {
|
||||
case SPX_REJECT:
|
||||
if (cnt > 0) {
|
||||
printf("[ SPX refuses authentication because %.*s ]\r\n",
|
||||
cnt, data);
|
||||
} else
|
||||
printf("[ SPX refuses authentication ]\r\n");
|
||||
auth_send_retry();
|
||||
return;
|
||||
case SPX_ACCEPT:
|
||||
printf("[ SPX accepts you ]\n");
|
||||
if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
|
||||
/*
|
||||
* Send over the encrypted challenge.
|
||||
*/
|
||||
input_token.value = (char *) data;
|
||||
input_token.length = cnt;
|
||||
|
||||
major_status = gss_init_sec_context(&status, /* minor stat */
|
||||
GSS_C_NO_CREDENTIAL, /* cred handle */
|
||||
&actual_ctxhandle, /* ctx handle */
|
||||
desired_targname, /* target name */
|
||||
GSS_C_NULL_OID, /* mech type */
|
||||
req_flags, /* req flags */
|
||||
0, /* time req */
|
||||
input_chan_bindings, /* chan binding */
|
||||
&input_token, /* input token */
|
||||
&actual_mech_type, /* actual mech */
|
||||
&output_token, /* output token */
|
||||
&ret_flags, /* ret flags */
|
||||
&lifetime_rec); /* time rec */
|
||||
|
||||
if (major_status != GSS_S_COMPLETE) {
|
||||
gss_display_status(&new_status,
|
||||
status,
|
||||
GSS_C_MECH_CODE,
|
||||
GSS_C_NULL_OID,
|
||||
&msg_ctx,
|
||||
&status_string);
|
||||
printf("[ SPX mutual response fails ... '%s' ]\r\n",
|
||||
status_string.value);
|
||||
auth_send_retry();
|
||||
return;
|
||||
}
|
||||
}
|
||||
auth_finished(ap, AUTH_USER);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
spx_status(ap, name, l, level)
|
||||
Authenticator *ap;
|
||||
char *name;
|
||||
size_t l;
|
||||
int level;
|
||||
{
|
||||
|
||||
gss_buffer_desc fullname_buffer, acl_file_buffer;
|
||||
gss_OID fullname_type;
|
||||
char acl_file[160], fullname[160];
|
||||
int major_status, status = 0;
|
||||
struct passwd pws, *pwd;
|
||||
char pwbuf[1024];
|
||||
|
||||
/*
|
||||
* hard code fullname to
|
||||
* "SPX:/C=US/O=Digital/OU=LKG/OU=Sphinx/OU=Users/CN=Kannan Alagappan"
|
||||
* and acl_file to "~kannan/.sphinx"
|
||||
*/
|
||||
|
||||
if (getpwnam_r(UserNameRequested, &pws, pwbuf, sizeof(pwbuf), &pwd)
|
||||
!= 0 || pwd == NULL) {
|
||||
return(AUTH_USER); /* not authenticated */
|
||||
}
|
||||
|
||||
strlcpy(acl_file, pwd->pw_dir, sizeof(acl_file));
|
||||
strlcat(acl_file, "/.sphinx", sizeof(acl_file));
|
||||
acl_file_buffer.value = acl_file;
|
||||
acl_file_buffer.length = strlen(acl_file);
|
||||
|
||||
major_status = gss_display_name(&status,
|
||||
src_name,
|
||||
&fullname_buffer,
|
||||
&fullname_type);
|
||||
|
||||
if (level < AUTH_USER)
|
||||
return(level);
|
||||
|
||||
major_status = gss__check_acl(&status, &fullname_buffer,
|
||||
&acl_file_buffer);
|
||||
|
||||
if (major_status == GSS_S_COMPLETE) {
|
||||
strlcpy(name, UserNameRequested, l);
|
||||
return(AUTH_VALID);
|
||||
} else {
|
||||
return(AUTH_USER);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
|
||||
#define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
|
||||
|
||||
void
|
||||
spx_printsub(data, cnt, buf, buflen)
|
||||
unsigned char *data, *buf;
|
||||
int cnt, buflen;
|
||||
{
|
||||
char lbuf[32];
|
||||
register int i;
|
||||
|
||||
buf[buflen-1] = '\0'; /* make sure its NULL terminated */
|
||||
buflen -= 1;
|
||||
|
||||
switch(data[3]) {
|
||||
case SPX_REJECT: /* Rejected (reason might follow) */
|
||||
strncpy((char *)buf, " REJECT ", buflen);
|
||||
goto common;
|
||||
|
||||
case SPX_ACCEPT: /* Accepted (name might follow) */
|
||||
strncpy((char *)buf, " ACCEPT ", buflen);
|
||||
common:
|
||||
BUMP(buf, buflen);
|
||||
if (cnt <= 4)
|
||||
break;
|
||||
ADDC(buf, buflen, '"');
|
||||
for (i = 4; i < cnt; i++)
|
||||
ADDC(buf, buflen, data[i]);
|
||||
ADDC(buf, buflen, '"');
|
||||
ADDC(buf, buflen, '\0');
|
||||
break;
|
||||
|
||||
case SPX_AUTH: /* Authentication data follows */
|
||||
strncpy((char *)buf, " AUTH", buflen);
|
||||
goto common2;
|
||||
|
||||
default:
|
||||
snprintf(lbuf, sizeof(lbuf), " %d (unknown)", data[3]);
|
||||
strncpy((char *)buf, lbuf, buflen);
|
||||
common2:
|
||||
BUMP(buf, buflen);
|
||||
for (i = 4; i < cnt; i++) {
|
||||
snprintf(lbuf, sizeof(lbuf), " %d", data[i]);
|
||||
strncpy((char *)buf, lbuf, buflen);
|
||||
BUMP(buf, buflen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef notdef
|
||||
|
||||
prkey(msg, key)
|
||||
char *msg;
|
||||
unsigned char *key;
|
||||
{
|
||||
register int i;
|
||||
printf("%s:", msg);
|
||||
for (i = 0; i < 8; i++)
|
||||
printf(" %3d", key[i]);
|
||||
printf("\r\n");
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user