Merge pull request #15 from Oichkatzelesfrettschen/eirikr/remove-netbsd-references-and-files

This commit is contained in:
Eirikr Hinngart 2025-05-30 11:42:35 -07:00 committed by GitHub
commit 1d9b0755f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 0 additions and 16378 deletions

View File

@ -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>

View File

@ -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?)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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);
}

View File

@ -1,4 +0,0 @@
# $NetBSD: shlib_version,v 1.5 2010/05/21 10:50:52 pooka Exp $
#
major=2
minor=0

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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>

View File

@ -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

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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>

View File

@ -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_ */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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';
}

View File

@ -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

View File

@ -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