mirror of
https://github.com/deadw00d/AROS.git
synced 2025-12-06 13:11:35 +00:00
add a w.i.p netinfo.device port, and move its header into the source directory.
This commit is contained in:
26
workbench/devs/netinfo/assert.h
Normal file
26
workbench/devs/netinfo/assert.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef USERGROUP_ASSERT_H
|
||||
#define USERGROUP_ASSERT_H
|
||||
|
||||
#include <proto/intuition.h>
|
||||
#include <clib/alib_protos.h>
|
||||
|
||||
#if defined(LC_LIBDEFS_FILE)
|
||||
#include LC_LIBDEFS_FILE
|
||||
#endif
|
||||
|
||||
static inline void __inline_InMsg(struct IntuitionBase *IntuitionBase, CONST_STRPTR __arg1, ...)
|
||||
{
|
||||
AROS_SLOWSTACKFORMAT_PRE(__arg1);
|
||||
struct EasyStruct libraryES;
|
||||
libraryES.es_StructSize = sizeof(libraryES);
|
||||
libraryES.es_Flags = 0;
|
||||
libraryES.es_Title = (STRPTR)MOD_NAME_STRING;
|
||||
libraryES.es_TextFormat = (STRPTR)__arg1;
|
||||
libraryES.es_GadgetFormat = "Continue";
|
||||
EasyRequestArgs(NULL, &libraryES, NULL, AROS_SLOWSTACKFORMAT_ARG(__arg1));
|
||||
AROS_SLOWSTACKFORMAT_POST(__arg1);
|
||||
}
|
||||
#define InMsg(...) \
|
||||
__inline_InMsg(IntuitionBase, __VA_ARGS__)
|
||||
|
||||
#endif /* USERGROUP_ASSERT_H */
|
||||
188
workbench/devs/netinfo/base.h
Normal file
188
workbench/devs/netinfo/base.h
Normal file
@ -0,0 +1,188 @@
|
||||
#ifndef _BASE_H_
|
||||
#define _BASE_H_
|
||||
/*
|
||||
* Netinfo device base. Define the device structure
|
||||
*
|
||||
* Copyright <20> 2025 The AROS Dev Team.
|
||||
* Copyright (c) 1993 Pekka Pessi
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef EXEC_LIBRARIES_H
|
||||
#include <exec/libraries.h>
|
||||
#endif
|
||||
|
||||
#ifndef DEVICES_NETINFO_H
|
||||
#include <devices/netinfo.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_TASKS_H
|
||||
#include <exec/tasks.h>
|
||||
#endif
|
||||
|
||||
#ifndef UTILITY_TAGITEM_H
|
||||
#include <utility/tagitem.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_IO_H
|
||||
#include <exec/io.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_DEVICES_H
|
||||
#include <exec/devices.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_ERRORS_H
|
||||
#include <exec/errors.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_MEMORY_H
|
||||
#include <exec/memory.h>
|
||||
#endif
|
||||
|
||||
#ifndef EXEC_SEMAPHORES_H
|
||||
#include <exec/semaphores.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_PRAGMAS
|
||||
#include <clib/exec_protos.h>
|
||||
#include <pragmas/exec_sysbase_pragmas.h>
|
||||
|
||||
#include <clib/dos_protos.h>
|
||||
#include <pragmas/dos_pragmas.h>
|
||||
|
||||
#define SysBase (nid->nid_ExecBase)
|
||||
#define DOSBase (nid->nid_DOSBase)
|
||||
#else
|
||||
#include <dos/notify.h>
|
||||
#include <dos/bptr.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Device base
|
||||
*/
|
||||
struct NetInfoDevice {
|
||||
struct Library nid_Lib;
|
||||
APTR nid_SegList;
|
||||
/* like there were no reference operator in C... */
|
||||
struct SignalSemaphore nid_Lock[1];
|
||||
APTR nid_ExecBase;
|
||||
APTR nid_DOSBase;
|
||||
struct MsgPort nid_Port[1]; /* Port to send requests */
|
||||
struct Message *nid_Death; /* Kill task by this message */
|
||||
struct MsgPort nid_NotifyPort[1]; /* Port for notify messages */
|
||||
struct List nid_Instances[1];
|
||||
struct NetInfoMap *nid_Maps[NETINFO_UNITS];
|
||||
};
|
||||
|
||||
#define nid_Task nid_Port->mp_SigTask
|
||||
#define nid_SigBit nid_Port->mp_SigBit
|
||||
|
||||
/* Internal constants */
|
||||
#define NETINFOSIZE ((sizeof(struct NetInfoDevice) +3) & ~3)
|
||||
#define NID_PRIORITY 1
|
||||
|
||||
typedef void (* DeviceCmd_t)(struct NetInfoDevice *, struct NetInfoReq *, struct NetInfoMap *);
|
||||
|
||||
/*
|
||||
* Structure for each netinfo map
|
||||
*/
|
||||
struct NetInfoMap {
|
||||
struct Node nim_Node[1];
|
||||
struct MsgPort *nim_Port;
|
||||
const struct MapMethods *nim_Methods;
|
||||
const DeviceCmd_t *nim_Commands;
|
||||
struct SignalSemaphore nim_PointerLock[1];
|
||||
struct List nim_Pointer[1]; /* under nid_Lock */
|
||||
struct SignalSemaphore nim_ReqLock[1];
|
||||
struct List nim_Rx[1];
|
||||
struct List nim_Wx[1];
|
||||
WORD nim_OpenCnt;
|
||||
WORD nim_Flags;
|
||||
const UBYTE *nim_Filename;
|
||||
struct SignalSemaphore nim_EntLock[1];
|
||||
struct List nim_Ent[1];
|
||||
struct NotifyRequest nim_Notify[1];
|
||||
};
|
||||
|
||||
#define NIMF_PARSED 0x0001
|
||||
#define NIMF_CHANGED 0x0002
|
||||
|
||||
#define nim_Name nim_Node->ln_Name
|
||||
|
||||
/*
|
||||
* Define map methods
|
||||
*/
|
||||
struct MapMethods {
|
||||
struct Ent * (*parse_ent)(struct NetInfoDevice *, register UBYTE *p);
|
||||
int (*print_out)(struct NetInfoDevice *, BPTR, struct Ent *);
|
||||
void * (*copy_out)(struct NetInfoReq *req, struct Ent *e);
|
||||
struct Ent * (*copy_in)(struct NetInfoDevice *, struct NetInfoReq *req);
|
||||
void (*cleanup)(struct NetInfoDevice *, struct NetInfoMap *);
|
||||
void (*membercmd)(struct NetInfoDevice *, struct NetInfoReq *,
|
||||
struct NetInfoMap *);
|
||||
void (*notify)(struct NetInfoDevice *, struct NetInfoMap *);
|
||||
};
|
||||
|
||||
#define DoNIMethod(cmd, req, unit)\
|
||||
((unit)->nim_Commands[cmd])(nid, (req), (unit))
|
||||
#define Method(method, unit)\
|
||||
(*((unit)->nim_Methods->method))
|
||||
|
||||
/*
|
||||
* Instance allocated for each opener (stored to io_Unit)
|
||||
*/
|
||||
struct NetInfoPointer {
|
||||
struct Node nip_Node[1];
|
||||
UBYTE nip_Flags;
|
||||
UBYTE nip_UnitNumber;
|
||||
struct NetInfoMap *nip_Map; /* backpointer */
|
||||
struct Ent *nip_Ent; /* latest entry read */
|
||||
};
|
||||
|
||||
#define nip_Name nip_Node->ln_Name
|
||||
|
||||
#if (0)
|
||||
/* Device initialization functions */
|
||||
ASM ULONG _LibInit(REG(a0) APTR seglist, REG(d0) struct Library *devbase);
|
||||
ASM ULONG _DevInit(BASEREG, REG(a0) APTR seglist);
|
||||
|
||||
/* Library entry points */
|
||||
ASM LONG _DevOpen(BASEREG, REG(a1) struct IORequest *req, REG(d0) ULONG unit,
|
||||
REG(d1) ULONG flags);
|
||||
ASM ULONG _DevClose(BASEREG, REG(a1) struct IORequest *req);
|
||||
ASM ULONG _DevExpunge(BASEREG);
|
||||
ASM ULONG _DevRes(void);
|
||||
ASM VOID _NetInfoBeginIO(BASEREG, REG(a1) struct NetInfoReq *req);
|
||||
ASM ULONG _NetInfoAbortIO(BASEREG, REG(a1) struct NetInfoReq *req);
|
||||
#endif
|
||||
|
||||
/* in server.c */
|
||||
ASM LONG NetInfoStartup(void);
|
||||
void NetInfoTask(struct NetInfoDevice *, struct Message *msg);
|
||||
struct NetInfoMap *InitNetInfoMap(struct NetInfoDevice *, struct MsgPort *, ULONG);
|
||||
void DeInitNetInfoMap(struct NetInfoDevice *, struct NetInfoMap *);
|
||||
struct Unit *CreateNewUnit(struct NetInfoDevice *, short unit);
|
||||
void ExpungeUnit(struct NetInfoDevice *, struct Unit *);
|
||||
void PerformIO(struct NetInfoDevice *, struct NetInfoReq *req);
|
||||
void TermIO(struct NetInfoReq *req);
|
||||
ULONG AbortReq(struct NetInfoDevice *, struct List *, struct NetInfoReq *);
|
||||
|
||||
/* Common method */
|
||||
void UnknownCommand(struct NetInfoDevice *, struct NetInfoReq *, struct NetInfoMap *);
|
||||
|
||||
/* support functions */
|
||||
struct NetInfoMap *CheckUnit(struct NetInfoDevice *, struct Unit *u);
|
||||
void FreeListVec(struct NetInfoDevice *, struct List *list);
|
||||
struct Node *FindNode(struct List *list, struct Node *node);
|
||||
char *strsep(register char **stringp, register const char *delim);
|
||||
|
||||
static __inline void InitList(struct List *list)
|
||||
{
|
||||
list->lh_Head = (struct Node*)&list->lh_Tail;
|
||||
list->lh_Tail = NULL;
|
||||
list->lh_TailPred = (struct Node*)&list->lh_Head;
|
||||
}
|
||||
|
||||
#endif /* _BASE_H_ */
|
||||
26
workbench/devs/netinfo/config.h
Normal file
26
workbench/devs/netinfo/config.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Configuration
|
||||
*
|
||||
* Copyright <20> 2025 The AROS Dev Team.
|
||||
* Copyright <20> 1993 Pekka Pessi
|
||||
*/
|
||||
|
||||
#ifdef __SASC
|
||||
#define ASM __asm
|
||||
#define SAVEDS __saveds
|
||||
#define FAR //For crypt.c, was defined as empty in Smakefile
|
||||
#define COMMON __far
|
||||
#define REG(x) register __ ## x
|
||||
#define USE_PRAGMAS 1
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#define ASM
|
||||
#define COMMON
|
||||
#define FAR
|
||||
#define SAVEDS
|
||||
#else
|
||||
#error "Unsupported compiler"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define INTERNAL static
|
||||
456
workbench/devs/netinfo/entries.c
Normal file
456
workbench/devs/netinfo/entries.c
Normal file
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* General DB routines
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#include "entries.h"
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
static struct NetInfoPointer *FindPointer(struct List *list, struct Ent*to);
|
||||
void GetByNameCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void GetByIDCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void ResetCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void ReadCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void WriteCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void UpdateCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
void MembersCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
|
||||
const static DeviceCmd_t map_cmds[NI_END] = {
|
||||
/* Standard commands */
|
||||
UnknownCommand, /* CMD_INVALID */
|
||||
ResetCmd, /* CMD_RESET */
|
||||
ReadCmd, /* CMD_READ */
|
||||
WriteCmd, /* CMD_WRITE */
|
||||
UpdateCmd, /* CMD_UPDATE */
|
||||
UnknownCommand, /* CMD_CLEAR */
|
||||
UnknownCommand, /* CMD_STOP */
|
||||
UnknownCommand, /* CMD_START */
|
||||
UnknownCommand, /* CMD_FLUSH */
|
||||
/* NetInfo commands */
|
||||
GetByIDCmd, /* NI_GETBYID */
|
||||
GetByNameCmd, /* NI_GETBYNAME */
|
||||
MembersCmd, /* NI_MEMBERS */
|
||||
};
|
||||
|
||||
static const init_map_func_t initMapFuncs[NETINFO_UNITS] = {
|
||||
InitPasswdMap,
|
||||
InitGroupMap,
|
||||
};
|
||||
|
||||
struct NetInfoMap *InitNetInfoMap(struct NetInfoDevice *nid, struct MsgPort * mp, ULONG mapno)
|
||||
{
|
||||
struct NetInfoMap *nim;
|
||||
#if defined(DEBUG)
|
||||
assert(mapno < 2);
|
||||
#endif
|
||||
if (nim = initMapFuncs[mapno](nid)) {
|
||||
nim->nim_Port = mp;
|
||||
nim->nim_Commands = map_cmds;
|
||||
|
||||
InitSemaphore(nim->nim_ReqLock);
|
||||
InitList(nim->nim_Rx);
|
||||
InitList(nim->nim_Wx);
|
||||
|
||||
InitSemaphore(nim->nim_EntLock);
|
||||
InitList(nim->nim_Ent);
|
||||
|
||||
InitSemaphore(nim->nim_PointerLock);
|
||||
InitList(nim->nim_Pointer);
|
||||
}
|
||||
return nim;
|
||||
}
|
||||
|
||||
void DeInitNetInfoMap(struct NetInfoDevice *nid, struct NetInfoMap *nim)
|
||||
{
|
||||
if (Method(cleanup, nim) != NULL)
|
||||
Method(cleanup, nim)(nid, nim);
|
||||
|
||||
FreeVec(nim);
|
||||
}
|
||||
|
||||
/*
|
||||
* NI_GETBYNAME, search an entry by name
|
||||
*/
|
||||
void GetByNameCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
struct Ent *e = InternalSetEnts(nid, nim);
|
||||
const UBYTE *name = (const UBYTE *)
|
||||
((struct NetInfoEnt*)req->io_Data)->nie_name;
|
||||
LONG retval = NIERR_NOTFOUND;
|
||||
|
||||
while (e = GetNextEnt(e)) {
|
||||
if (strcmp(e->e_name, name) == 0) {
|
||||
if (Method(copy_out, nim)(req, e)) {
|
||||
retval = 0;
|
||||
} else {
|
||||
retval = NIERR_TOOSMALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
req->io_Error = retval;
|
||||
|
||||
InternalEndEnts(nid, nim);
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* NI_GETBYID, Search an entry by ID
|
||||
*/
|
||||
void GetByIDCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
struct Ent *e = InternalSetEnts(nid, nim);
|
||||
LONG id = ((struct NetInfoEnt*)req->io_Data)->nie_id;
|
||||
BYTE retval = NIERR_NOTFOUND;
|
||||
|
||||
while (e = GetNextEnt(e)) {
|
||||
if (e->e_id == id) {
|
||||
if (Method(copy_out, nim)(req, e)) {
|
||||
retval = 0;
|
||||
} else {
|
||||
retval = NIERR_TOOSMALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
req->io_Error = retval;
|
||||
|
||||
InternalEndEnts(nid, nim);
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_RESET, start reading the database in sequential order
|
||||
*/
|
||||
void ResetCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
struct NetInfoPointer *p = (struct NetInfoPointer *)req->io_Unit;
|
||||
|
||||
p->nip_Ent = (void *)InternalSetEnts(nid, nim);
|
||||
InternalEndEnts(nid, nim);
|
||||
req->io_Error = 0;
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_READ, get next entry
|
||||
*/
|
||||
void ReadCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
struct NetInfoPointer *p = (struct NetInfoPointer *)req->io_Unit;
|
||||
struct Ent *e;
|
||||
BYTE retval;
|
||||
|
||||
InternalSetEnts(nid, nim);
|
||||
e = p->nip_Ent;
|
||||
if (p->nip_Ent && (p->nip_Ent = GetNextEnt(e))) {
|
||||
if (Method(copy_out, nim)(req, p->nip_Ent)) {
|
||||
retval = 0;
|
||||
} else {
|
||||
retval = NIERR_TOOSMALL;
|
||||
}
|
||||
} else {
|
||||
retval = NIERR_NOTFOUND;
|
||||
}
|
||||
InternalEndEnts(nid, nim);
|
||||
|
||||
req->io_Error = retval;
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_WRITE
|
||||
*/
|
||||
void WriteCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
struct Ent *e, *new_e;
|
||||
const UBYTE *name = ((struct NetInfoPasswd *)req->io_Data)->pw_name;
|
||||
|
||||
if (new_e = Method(copy_in, nim)(nid, req)) {
|
||||
/* Exclusive lock for writing */
|
||||
DbMapLock(nim);
|
||||
|
||||
e = InternalSetEnts(nid, nim);
|
||||
|
||||
while (e = GetNextEnt(e)) {
|
||||
if (strcmp(e->e_name, name) == 0) {
|
||||
/* A match was found - add new */
|
||||
Insert(nim->nim_Ent, (struct Node *)new_e, (struct Node *)e);
|
||||
|
||||
/* Remove old */
|
||||
Remove((struct Node *)e);
|
||||
|
||||
/* Update pointers */
|
||||
ObtainSemaphore(nim->nim_PointerLock);
|
||||
{
|
||||
struct NetInfoPointer *nip;
|
||||
if (nip = FindPointer(nim->nim_Pointer, e)) {
|
||||
nip->nip_Ent = (void *)new_e;
|
||||
}
|
||||
}
|
||||
ReleaseSemaphore(nim->nim_PointerLock);
|
||||
|
||||
/* Free old */
|
||||
FreeVec(e);
|
||||
|
||||
new_e = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A new entry?
|
||||
*/
|
||||
if (new_e != NULL) {
|
||||
AddTail(nim->nim_Ent, (struct Node *)new_e);
|
||||
}
|
||||
|
||||
req->io_Error = 0;
|
||||
InternalEndEnts(nid, nim);
|
||||
|
||||
nim->nim_Flags |= NIMF_CHANGED;
|
||||
DbMapUnlock(nim);
|
||||
} else {
|
||||
/* copy_in method will set the io_Error */
|
||||
}
|
||||
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* CMD_UPDATE
|
||||
*/
|
||||
void UpdateCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
BYTE retval = 0;
|
||||
|
||||
if ((nim->nim_Flags & NIMF_CHANGED) != 0) {
|
||||
UBYTE newname[128], oldname[128];
|
||||
BPTR newfile;
|
||||
DbMapLock(nim);
|
||||
if ((nim->nim_Flags & NIMF_CHANGED) == 0)
|
||||
goto exit;
|
||||
|
||||
newname[sizeof(newname)-1] = '\0';
|
||||
strncpy(newname, nim->nim_Filename, sizeof(newname)-1);
|
||||
strncat(newname, ".new", sizeof(newname)-1);
|
||||
|
||||
oldname[sizeof(oldname)-1] = '\0';
|
||||
strncpy(oldname, nim->nim_Filename, sizeof(oldname)-1);
|
||||
strncat(oldname, ".old", sizeof(oldname)-1);
|
||||
|
||||
if (newfile = Open(newname, MODE_NEWFILE)) {
|
||||
struct Node *entry, *next;
|
||||
|
||||
retval = 0;
|
||||
|
||||
for (entry = nim->nim_Ent->lh_Head;
|
||||
next = entry->ln_Succ;
|
||||
entry = next) {
|
||||
retval = Method(print_out, nim)(nid, newfile, (struct Ent *)entry);
|
||||
if (retval)
|
||||
break;
|
||||
}
|
||||
Close(newfile);
|
||||
|
||||
if (retval == 0) {
|
||||
/* Now we are supposed to move newfile to file */
|
||||
DeleteFile(oldname);
|
||||
Rename(nim->nim_Filename, oldname);
|
||||
if (Rename(newname, nim->nim_Filename))
|
||||
nim->nim_Flags &= NIMF_CHANGED;
|
||||
else
|
||||
retval = NIERR_ACCESS;
|
||||
}
|
||||
} else {
|
||||
retval = NIERR_ACCESS;
|
||||
}
|
||||
exit:
|
||||
DbMapUnlock(nim);
|
||||
}
|
||||
|
||||
req->io_Error = retval;
|
||||
TermIO(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* NI_MEMBERS
|
||||
*/
|
||||
void MembersCmd(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
if (Method(membercmd, nim) != NULL) {
|
||||
Method(membercmd, nim)(nid, req, nim);
|
||||
} else {
|
||||
req->io_Error = IOERR_NOCMD;
|
||||
TermIO(req);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a pointer to this entry
|
||||
*/
|
||||
static struct NetInfoPointer *FindPointer(struct List *list, struct Ent *to)
|
||||
{
|
||||
struct NetInfoPointer *entry, *next;
|
||||
|
||||
for (entry = (struct NetInfoPointer *)list->lh_Head;
|
||||
next = (struct NetInfoPointer *)entry->nip_Node->ln_Succ;
|
||||
entry = next)
|
||||
if (entry->nip_Ent == to) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for map
|
||||
*/
|
||||
struct NetInfoMap *CheckUnit(struct NetInfoDevice *nid, struct Unit *u)
|
||||
{
|
||||
struct NetInfoPointer *nip = (struct NetInfoPointer *)u;
|
||||
|
||||
if (nip != NULL)
|
||||
return nip->nip_Map;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse group database if needed
|
||||
*/
|
||||
struct Ent *InternalSetEnts(struct NetInfoDevice *nid, struct NetInfoMap *nim)
|
||||
{
|
||||
DbMapLockShared(nim);
|
||||
|
||||
if ((nim->nim_Flags & NIMF_PARSED) == 0) {
|
||||
int was_too_long = 0;
|
||||
UBYTE *p, *line = NULL;
|
||||
BPTR fh = NULL;
|
||||
struct Ent *ent;
|
||||
|
||||
/* We can not get exclusive lock if we have shared lock */
|
||||
DbMapUnlock(nim);
|
||||
/* Exclusive lock for writing */
|
||||
DbMapLock(nim);
|
||||
if ((nim->nim_Flags & NIMF_PARSED) != 0)
|
||||
goto error;
|
||||
|
||||
line = AllocVec(MAXLINELENGTH + 1, MEMF_PUBLIC);
|
||||
fh = Open((STRPTR)nim->nim_Filename, MODE_OLDFILE);
|
||||
|
||||
if (!line || !fh)
|
||||
goto error;
|
||||
|
||||
/* Free old entries */
|
||||
FreeListVec(nid, nim->nim_Ent);
|
||||
|
||||
/* Invalidate pointers to old database */
|
||||
ObtainSemaphore(nim->nim_PointerLock);
|
||||
{
|
||||
struct NetInfoPointer *nip, *next;
|
||||
|
||||
for (nip = (struct NetInfoPointer *)nim->nim_Pointer->lh_Head;
|
||||
next = (struct NetInfoPointer *)nip->nip_Node->ln_Succ;
|
||||
nip = next) {
|
||||
nip->nip_Ent = NULL;
|
||||
}
|
||||
}
|
||||
ReleaseSemaphore(nim->nim_PointerLock);
|
||||
|
||||
line[MAXLINELENGTH] = '\0';
|
||||
|
||||
while (p = FGets(fh, line, MAXLINELENGTH)) {
|
||||
while (*p && *p != '\n')
|
||||
p++;
|
||||
if (!*p) {
|
||||
/* Line is too long */
|
||||
was_too_long = 1;
|
||||
continue;
|
||||
}
|
||||
if (was_too_long) {
|
||||
/* Rest of a line */
|
||||
was_too_long = 0;
|
||||
continue;
|
||||
}
|
||||
if (ent = Method(parse_ent, nim)(nid, line))
|
||||
AddTail(nim->nim_Ent, (struct Node *)ent);
|
||||
}
|
||||
nim->nim_Flags |= NIMF_PARSED;
|
||||
|
||||
/* Ask for notifies */
|
||||
if (nim->nim_Methods->notify != NULL &&
|
||||
nim->nim_Notify->nr_UserData == 0) {
|
||||
memset(nim->nim_Notify, 0, sizeof *nim->nim_Notify);
|
||||
nim->nim_Notify->nr_Name = (STRPTR)nim->nim_Filename;
|
||||
nim->nim_Notify->nr_Flags = NRF_SEND_MESSAGE;
|
||||
nim->nim_Notify->nr_stuff.nr_Msg.nr_Port = nid->nid_NotifyPort;
|
||||
nim->nim_Notify->nr_UserData = (IPTR) nim;
|
||||
StartNotify(nim->nim_Notify);
|
||||
}
|
||||
|
||||
error:
|
||||
if (line) FreeVec(line);
|
||||
if (fh) Close(fh);
|
||||
|
||||
/* Downgrade to a shared lock */
|
||||
DbMapUnlock(nim);
|
||||
DbMapLockShared(nim);
|
||||
}
|
||||
|
||||
return (struct Ent *)nim->nim_Ent;
|
||||
}
|
||||
|
||||
void InternalEndEnts(struct NetInfoDevice *nid, struct NetInfoMap *nim)
|
||||
{
|
||||
DbMapUnlock(nim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return next entry
|
||||
*/
|
||||
struct Ent *GetNextEnt(struct Ent *e)
|
||||
{
|
||||
e = (struct Ent *)e->e_node.ln_Succ;
|
||||
|
||||
if (e->e_node.ln_Succ)
|
||||
return e;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark as unparsed (when map has received DOS notify)
|
||||
*/
|
||||
void EntHandleNotify(struct NetInfoDevice *nid, struct NetInfoMap *nim)
|
||||
{
|
||||
DbMapLockShared(nim);
|
||||
nim->nim_Flags &= ~NIMF_PARSED;
|
||||
DbMapUnlock(nim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all entries
|
||||
*/
|
||||
void EntCleanup(struct NetInfoDevice *nid, struct NetInfoMap *nim)
|
||||
{
|
||||
DbMapLock(nim);
|
||||
FreeListVec(nid, nim->nim_Ent);
|
||||
/* End notifies */
|
||||
if (nim->nim_Notify->nr_UserData != 0) {
|
||||
EndNotify(nim->nim_Notify);
|
||||
nim->nim_Notify->nr_UserData = 0;
|
||||
}
|
||||
DbMapUnlock(nim);
|
||||
}
|
||||
98
workbench/devs/netinfo/entries.h
Normal file
98
workbench/devs/netinfo/entries.h
Normal file
@ -0,0 +1,98 @@
|
||||
#ifndef _ENTRIES_H_
|
||||
#define _ENTRIES_H_
|
||||
/*
|
||||
* entries.h --- db units
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include "base.h"
|
||||
|
||||
struct NetInfoEnt {
|
||||
UBYTE *nie_name;
|
||||
ULONG nie_fill;
|
||||
ULONG nie_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Common values are represented with this structure
|
||||
*/
|
||||
struct Ent {
|
||||
struct Node e_node;
|
||||
UWORD e_tlen; /* size of text data */
|
||||
UBYTE *e_name;
|
||||
LONG e_pwd;
|
||||
LONG e_id;
|
||||
};
|
||||
|
||||
struct PasswdEnt {
|
||||
struct Node pe_node;
|
||||
UWORD pe_tlen;
|
||||
struct NetInfoPasswd pe_passwd[1];
|
||||
};
|
||||
|
||||
/* we may have an extended version of passwd */
|
||||
#define PASSWDFIELDS 7
|
||||
|
||||
struct GroupEnt {
|
||||
struct Node ge_node;
|
||||
UWORD ge_tlen;
|
||||
struct NetInfoGroup ge_group[1];
|
||||
ULONG ge_nmembers; /* actually, # of members + 1 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Entry Node Type
|
||||
*/
|
||||
#define ENT_PASSWD 30
|
||||
#define ENT_GROUP 31
|
||||
|
||||
/*
|
||||
* The changed entries are marked
|
||||
*/
|
||||
#define ENT_CHANGED 1
|
||||
|
||||
/*
|
||||
* Maximum entry length
|
||||
*/
|
||||
#define MAXLINELENGTH 1024
|
||||
|
||||
/*
|
||||
* Datastruct NetInfoDevice * paths
|
||||
*/
|
||||
#define _PATH_PASSWD "AmiTCP:db/passwd"
|
||||
#define _PATH_GROUP "AmiTCP:db/group"
|
||||
|
||||
/*
|
||||
* As this far there are no quick commands
|
||||
* we bother to lock only niu_ReqLock
|
||||
*/
|
||||
#define DbMapLock(u)
|
||||
#define DbMapLockShared(u)
|
||||
#define DbMapUnlock(u)
|
||||
|
||||
/* common methods in entries.c */
|
||||
void EntCleanup(struct NetInfoDevice *, struct NetInfoMap *nim);
|
||||
void EntHandleNotify(struct NetInfoDevice *, struct NetInfoMap *nim);
|
||||
|
||||
typedef struct NetInfoMap *(*init_map_func_t)(struct NetInfoDevice *);
|
||||
struct NetInfoMap *InitPasswdMap(struct NetInfoDevice *);
|
||||
struct NetInfoMap *InitGroupMap(struct NetInfoDevice *);
|
||||
|
||||
/* Other prototypes */
|
||||
struct Ent *InternalSetEnts(struct NetInfoDevice *, struct NetInfoMap *nim);
|
||||
void InternalEndEnts(struct NetInfoDevice *, struct NetInfoMap *nim);
|
||||
struct Ent *GetNextEnt(struct Ent *e);
|
||||
|
||||
/* Utility */
|
||||
static __inline char *stpcopy(char *to, const char *from)
|
||||
{
|
||||
while (*to++ = *from++)
|
||||
;
|
||||
return to;
|
||||
}
|
||||
|
||||
#endif /* _ENTRIES_H_ */
|
||||
325
workbench/devs/netinfo/groupunit.c
Normal file
325
workbench/devs/netinfo/groupunit.c
Normal file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
* groupunit.c --- unit for groups
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#include "entries.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
static void *CopyEntToGroup(struct NetInfoReq *req, struct Ent *e);
|
||||
static struct Ent *CopyGroupToEnt(struct NetInfoDevice *nid, struct NetInfoReq *req);
|
||||
static struct Ent *ParseGroup(struct NetInfoDevice *nid, register UBYTE *p);
|
||||
static int PrintGroup(struct NetInfoDevice *nid, BPTR file, struct Ent *e);
|
||||
static void GetGroups(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
|
||||
const static struct MapMethods group_methods[1] = {
|
||||
{
|
||||
/* Other methods */
|
||||
ParseGroup,
|
||||
PrintGroup,
|
||||
CopyEntToGroup,
|
||||
CopyGroupToEnt,
|
||||
EntCleanup,
|
||||
GetGroups,
|
||||
EntHandleNotify,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate and initialize group map
|
||||
*/
|
||||
struct NetInfoMap *InitGroupMap(struct NetInfoDevice *nid)
|
||||
{
|
||||
struct NetInfoMap *nim = AllocVec(sizeof(*nim), MEMF_CLEAR|MEMF_PUBLIC);
|
||||
|
||||
if (nim) {
|
||||
nim->nim_Methods = group_methods;
|
||||
nim->nim_Name = "group";
|
||||
nim->nim_Filename = _PATH_GROUP;
|
||||
}
|
||||
|
||||
return nim;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an GroupEnt structure to group structure
|
||||
*/
|
||||
static void *CopyEntToGroup(struct NetInfoReq *req, struct Ent *e)
|
||||
{
|
||||
struct GroupEnt *ge = (struct GroupEnt *)e;
|
||||
struct NetInfoGroup *gr = req->io_Data;
|
||||
STRPTR *mto = (STRPTR *)(gr + 1);
|
||||
UBYTE *to = (UBYTE *)(mto + ge->ge_nmembers);
|
||||
|
||||
ULONG size = req->io_Length;
|
||||
ULONG actual = sizeof(*gr) + ge->ge_tlen + ge->ge_nmembers * sizeof(UBYTE *);
|
||||
|
||||
UBYTE **mfrom;
|
||||
|
||||
req->io_Actual = actual;
|
||||
|
||||
if (size < actual) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy group strings */
|
||||
to = stpcopy(gr->gr_name = to, ge->ge_group->gr_name);
|
||||
to = stpcopy(gr->gr_passwd = to, ge->ge_group->gr_passwd);
|
||||
/* .. and id */
|
||||
gr->gr_gid = ge->ge_group->gr_gid;
|
||||
|
||||
/* .. and members */
|
||||
for (gr->gr_mem = mto, mfrom = ge->ge_group->gr_mem;
|
||||
*mfrom && (*mto++ = to); ) {
|
||||
to = stpcopy(to, *mfrom++);
|
||||
}
|
||||
*mto = NULL;
|
||||
#if defined(DEBUG)
|
||||
assert(to <= (UBYTE *)req->io_Data + req->io_Length);
|
||||
#endif
|
||||
|
||||
return gr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an group structure into a internal entry
|
||||
*/
|
||||
static struct Ent *CopyGroupToEnt(struct NetInfoDevice *nid, struct NetInfoReq *req)
|
||||
{
|
||||
struct NetInfoGroup *gr = (struct NetInfoGroup*)req->io_Data;
|
||||
struct GroupEnt *ge;
|
||||
UBYTE *to, **mem, **mto;
|
||||
short nmem = 1;
|
||||
ULONG txtlen = 0;
|
||||
|
||||
/*
|
||||
* These cause EFAULT
|
||||
*/
|
||||
if (gr == NULL || (1 & (IPTR)gr) != 0 ||
|
||||
gr->gr_name == NULL ||
|
||||
gr->gr_passwd == NULL ||
|
||||
gr->gr_mem == NULL || (1 & (IPTR)gr->gr_mem)) {
|
||||
req->io_Error = IOERR_BADADDRESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (mem = gr->gr_mem; *mem; mem++, nmem++) {
|
||||
if (*mem == NULL) {
|
||||
req->io_Error = IOERR_BADADDRESS;
|
||||
return NULL;
|
||||
}
|
||||
txtlen += strlen(*mem) + 1;
|
||||
}
|
||||
|
||||
txtlen += strlen(gr->gr_name) + strlen(gr->gr_passwd) + 2;
|
||||
|
||||
ge = AllocVec(sizeof(*ge) + nmem * sizeof(*mem) + txtlen, MEMF_CLEAR);
|
||||
if (ge == NULL) {
|
||||
req->io_Error = NIERR_NOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ge->ge_node.ln_Type = ENT_GROUP;
|
||||
ge->ge_node.ln_Pri = ENT_CHANGED;
|
||||
ge->ge_tlen = txtlen;
|
||||
ge->ge_group->gr_gid = gr->gr_gid;
|
||||
|
||||
ge->ge_nmembers = nmem;
|
||||
ge->ge_group->gr_mem = mto = (UBYTE **)(ge + 1);
|
||||
to = (UBYTE *)(mto + nmem);
|
||||
/* Copy normal strings.. */
|
||||
to = stpcopy(ge->ge_group->gr_name = to, gr->gr_name);
|
||||
to = stpcopy(ge->ge_group->gr_passwd = to, gr->gr_passwd);
|
||||
/* ..and members */
|
||||
for (mem = gr->gr_mem; *mem; mem++) {
|
||||
to = stpcopy(*mto++ = to, *mem);
|
||||
nmem--;
|
||||
}
|
||||
*mem = NULL;
|
||||
#if defined(DEBUG)
|
||||
assert(to == ge->ge_group->gr_name + txtlen);
|
||||
assert(nmem == 1);
|
||||
#endif
|
||||
return (struct Ent *)ge;
|
||||
}
|
||||
|
||||
/****** netinfo.device/group ***********************************************
|
||||
|
||||
NAME
|
||||
group - format of the group permissions file
|
||||
|
||||
DESCRIPTION
|
||||
The file <AmiTCP:db/group> consists of newline separated ASCII
|
||||
records, one per group, containing four bar `|' separated fields.
|
||||
These fields are as follows:
|
||||
|
||||
group Name of the group.
|
||||
passwd Group's encrypted password.
|
||||
gid The group's decimal ID.
|
||||
member Group members.
|
||||
|
||||
The group field is the group name used for granting file access to
|
||||
users who are members of the group. The gid field is the number
|
||||
associated with the group name. They should both be unique across
|
||||
the system (and often across a group of systems) since they control
|
||||
file access. The passwd field is an optional encrypted password.
|
||||
This field is rarely used and an asterisk is normally placed in it
|
||||
rather than leaving it blank. The member field contains the names
|
||||
of users granted the priviledges of group. The member names are
|
||||
separated by commas with out spaces or newlines. A user is
|
||||
automatically in a group if that group was specified in their
|
||||
AmiTCP:db/passwd entry and does not need to be added to that group
|
||||
in the AmiTCP:db/group file.
|
||||
|
||||
FILES
|
||||
AmiTCP:db/group
|
||||
|
||||
SEE ALSO
|
||||
passwd
|
||||
|
||||
HISTORY
|
||||
A group file format appeared in Version 6 AT&T UNIX.
|
||||
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parse the group entry
|
||||
*/
|
||||
static struct Ent *ParseGroup(struct NetInfoDevice *nid, register UBYTE *p)
|
||||
{
|
||||
int l;
|
||||
UBYTE *np, *name, *pass, *id_s, *memlist, **members;
|
||||
ULONG nmembers;
|
||||
LONG gid, txtlen = 0;
|
||||
|
||||
struct GroupEnt *ge;
|
||||
|
||||
np = p;
|
||||
|
||||
name = strsep((char **)&np, "|\n");
|
||||
pass = strsep((char **)&np, "|\n");
|
||||
id_s = strsep((char **)&np, "|\n");
|
||||
memlist = np;
|
||||
if ((l = StrToLong(id_s, &gid)) <= 0 || id_s[l] != '\0')
|
||||
return NULL;
|
||||
for (nmembers = 1; (p = strsep((char **)&np, ", \n")) && np;) {
|
||||
if (*p) nmembers++;
|
||||
else txtlen--;
|
||||
if (*np == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(np != NULL);
|
||||
#endif
|
||||
|
||||
if (!name || !pass || !id_s || !np)
|
||||
return NULL;
|
||||
|
||||
txtlen += np - name - (memlist - id_s);
|
||||
ge = AllocVec(sizeof(*ge) + nmembers * sizeof(UBYTE*) + txtlen, MEMF_CLEAR);
|
||||
if (!ge)
|
||||
return NULL;
|
||||
|
||||
ge->ge_node.ln_Type = ENT_GROUP;
|
||||
|
||||
ge->ge_nmembers = nmembers;
|
||||
ge->ge_tlen = txtlen;
|
||||
|
||||
members = (UBYTE **)(ge + 1);
|
||||
p = (UBYTE *)(members + nmembers);
|
||||
|
||||
/* Copy name */
|
||||
p = stpcopy(ge->ge_group->gr_name = p, name);
|
||||
p = stpcopy(ge->ge_group->gr_passwd = p, pass);
|
||||
|
||||
ge->ge_group->gr_gid = gid;
|
||||
ge->ge_group->gr_mem = members;
|
||||
|
||||
/* Copy the memberlist */
|
||||
while (nmembers > 1) {
|
||||
if (*memlist) {
|
||||
nmembers--;
|
||||
*members++ = p;
|
||||
while (*p++ = *memlist++)
|
||||
;
|
||||
} else {
|
||||
memlist++;
|
||||
}
|
||||
}
|
||||
*members = NULL;
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(p == ge->ge_group->gr_name + txtlen);
|
||||
#endif
|
||||
|
||||
return (struct Ent *)ge;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out an group entry
|
||||
*/
|
||||
static int PrintGroup(struct NetInfoDevice *nid, BPTR file, struct Ent *e)
|
||||
{
|
||||
struct GroupEnt *ge = (struct GroupEnt *)e;
|
||||
UBYTE **member = ge->ge_group->gr_mem;
|
||||
UBYTE *fmt = "%s";
|
||||
|
||||
VFPrintf(file, "%s|%s|%ld|", (RAWARG)ge->ge_group);
|
||||
while (*member) {
|
||||
FPrintf(file, fmt, *member++);
|
||||
fmt = ",%s";
|
||||
}
|
||||
FPutC(file, '\n');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute NI_MEMBERS command
|
||||
*/
|
||||
static void GetGroups(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
int maxgroups = req->io_Length / sizeof(LONG);
|
||||
LONG *groups = (LONG *)req->io_Data;
|
||||
STRPTR uname;
|
||||
register int ngroups = 0;
|
||||
register struct GroupEnt *ge;
|
||||
register int i;
|
||||
BYTE retval = 0;
|
||||
|
||||
#if __WORDSIZE == 32
|
||||
uname = (STRPTR)req->io_Offset;
|
||||
#else
|
||||
uname = (STRPTR)(((IPTR)req->io_Offset << 32) | req->io_Actual);
|
||||
#endif
|
||||
|
||||
ge = (struct GroupEnt *)InternalSetEnts(nid, nim);
|
||||
|
||||
while (ge = (struct GroupEnt *)GetNextEnt((struct Ent *)ge)) {
|
||||
for (i = 0; ge->ge_group->gr_mem[i]; i++)
|
||||
if (strcmp(ge->ge_group->gr_mem[i], uname) == 0) {
|
||||
if (ngroups == maxgroups) {
|
||||
retval = NIERR_TOOSMALL;
|
||||
goto toomany;
|
||||
}
|
||||
groups[ngroups++] = ge->ge_group->gr_gid;
|
||||
}
|
||||
}
|
||||
|
||||
toomany:
|
||||
InternalEndEnts(nid, nim);
|
||||
|
||||
req->io_Actual = ngroups * sizeof(LONG);
|
||||
req->io_Error = retval;
|
||||
TermIO(req);
|
||||
}
|
||||
78
workbench/devs/netinfo/misc.c
Normal file
78
workbench/devs/netinfo/misc.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* misc.c
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
/*
|
||||
* Free nodes of a list (they should all be allocated with AllocVec())
|
||||
*/
|
||||
void FreeListVec(struct NetInfoDevice *nid, struct List *list)
|
||||
{
|
||||
struct Node *entry, *next;
|
||||
|
||||
for (entry = list->lh_Head; next = entry->ln_Succ; entry = next) {
|
||||
Remove(entry);
|
||||
FreeVec(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that a node is in list
|
||||
* return node if it is, NULL otherwise
|
||||
*/
|
||||
struct Node *FindNode(struct List *list, struct Node *node)
|
||||
{
|
||||
struct Node *entry, *next;
|
||||
|
||||
for (entry = list->lh_Head; next = entry->ln_Succ; entry = next)
|
||||
if (entry == node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get next token from string *stringp, where tokens are nonempty
|
||||
* strings separated by characters from delim.
|
||||
*
|
||||
* Writes NULs into the string at *stringp to end tokens.
|
||||
* delim need not remain constant from call to call.
|
||||
* On return, *stringp points past the last NUL written (if there might
|
||||
* be further tokens), or is NULL (if there are definitely no more tokens).
|
||||
*
|
||||
* If *stringp is NULL, strtoken returns NULL.
|
||||
*/
|
||||
char *strsep(register char **stringp, register const char *delim)
|
||||
{
|
||||
register char *s;
|
||||
register const char *spanp;
|
||||
register int c, sc;
|
||||
char *tok;
|
||||
|
||||
if ((s = *stringp) == NULL)
|
||||
return (NULL);
|
||||
for (tok = s;;) {
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = 0;
|
||||
*stringp = s;
|
||||
return (tok);
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
}
|
||||
26
workbench/devs/netinfo/mmakefile.src
Normal file
26
workbench/devs/netinfo/mmakefile.src
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
include $(SRCDIR)/config/aros.cfg
|
||||
|
||||
FILES := \
|
||||
netinfo \
|
||||
server \
|
||||
entries \
|
||||
groupunit \
|
||||
passwdunit \
|
||||
misc
|
||||
|
||||
#MM- workbench-devs-common: workbench-devs-netinfo
|
||||
|
||||
#MM- workbench-devs-quick: workbench-devs-netinfo-quick
|
||||
|
||||
#USER_CFLAGS := -DDEBUG=1
|
||||
USER_LDFLAGS := -static
|
||||
|
||||
%build_module mmake=workbench-devs-netinfo \
|
||||
modname=netinfo modtype=device \
|
||||
files=$(FILES)
|
||||
|
||||
INCLUDE_FILES = include/netinfo.h
|
||||
%copy_includes path=devices dir=include
|
||||
|
||||
%common
|
||||
309
workbench/devs/netinfo/netinfo.c
Normal file
309
workbench/devs/netinfo/netinfo.c
Normal file
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* netinfo.c --- netinfo.device main functions
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
/****** netinfo.device/--background-- **************************************
|
||||
|
||||
PURPOSE
|
||||
|
||||
The netinfo.device is intended to access various information from
|
||||
network database. It provides an uniform and well-defined interface
|
||||
to databases, so it is easy to adopt clients to different
|
||||
environments. There is a separate unit for each database.
|
||||
|
||||
Currently the netinfo.device supports access to local password and
|
||||
group files. As a new feature since last release it supports file
|
||||
notification.
|
||||
|
||||
The device file is located to "AmiTCP:devs/netinfo.device". It is
|
||||
recommended that the OpenDevice() call is given the macro NETINFONAME
|
||||
as device name.
|
||||
|
||||
OVERVIEW
|
||||
Short overview of implemented IO commands is as follows:
|
||||
|
||||
CMD_RESET - reset sequential access
|
||||
This command restarts the sequential database reading.
|
||||
Inputs: none
|
||||
Results:
|
||||
* io_Error contains possaible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
CMD_READ - read next entry
|
||||
Inputs:
|
||||
* io_Data contains buffer for database entry. The buffer will
|
||||
be filled wtih entry data upon successfull execution.
|
||||
* io_Length contains database len
|
||||
Results:
|
||||
* io_Actual contains length of the database entry
|
||||
* io_Error contains possaible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
CMD_WRITE - alter the database
|
||||
This command adds a new database entry or replace an old entry.
|
||||
If a matching entry with same name is found, it is replaced with
|
||||
the new entry.
|
||||
|
||||
Inputs:
|
||||
* io_Data contains pointer for database entry structure
|
||||
Results:
|
||||
* io_Actual contains length of the database entry
|
||||
* io_Error contains possible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
CMD_UPDATE - copy the previous changes to permanent store
|
||||
|
||||
This command updates the permanent copies of database. The
|
||||
netinfo.device does not ensure that entries updated with
|
||||
CMD_WRITE will be available by CMD_READ or written to permanent
|
||||
store before the CMD_UPDATE is executed.
|
||||
|
||||
Inputs: none
|
||||
Results:
|
||||
* io_Error contains possible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
NI_BYNAME - search by name
|
||||
Inputs:
|
||||
* io_Data contains buffer for database entry. The buffer will
|
||||
be filled wtih entry data upon successfull execution. The name
|
||||
member of structure should be pointer to a C string containing
|
||||
the name of desired entry
|
||||
* io_Length contains database len
|
||||
Results:
|
||||
* io_Actual contains length of the database entry
|
||||
* io_Error contains possaible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
NI_BYUID - search by ID
|
||||
Inputs:
|
||||
* io_Data contains buffer for database entry. The buffer will
|
||||
be filled wtih entry data upon successfull execution. The ID
|
||||
member of structure should be set to desired value.
|
||||
* io_Length contains database len
|
||||
Results:
|
||||
* io_Actual contains length of the database entry
|
||||
* io_Error contains possaible error code or 0 if command was
|
||||
successfull
|
||||
|
||||
NI_MEMBERS - find out memberships
|
||||
This command is implemented only for group unit. It collects
|
||||
the IDs of groups which have a given user as member.
|
||||
|
||||
Inputs:
|
||||
* io_Data is address to LONG array which is filled with group
|
||||
IDs
|
||||
* io_Length is the length of the array in bytes
|
||||
* io_Offset is a pointer to C string containing the name of
|
||||
user whose memberships are desired
|
||||
Results:
|
||||
* io_Actual contains length of the group ID array in bytes
|
||||
* io_Error contains possaible error code or 0 if command was
|
||||
successfull.
|
||||
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#include "base.h"
|
||||
#include <dos/dostags.h>
|
||||
|
||||
#if defined(LC_LIBDEFS_FILE)
|
||||
#include LC_LIBDEFS_FILE
|
||||
|
||||
/*
|
||||
* Device initialization routine
|
||||
* Do only things that won't Wait()
|
||||
*/
|
||||
static int NetInfo__DevInit(LIBBASETYPEPTR LIBBASE)
|
||||
{
|
||||
LIBBASE->nid_Task = NULL;
|
||||
InitSemaphore(LIBBASE->nid_Lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int NetInfo__DevOpen(LIBBASETYPEPTR LIBBASE,
|
||||
struct IORequest *req,
|
||||
ULONG unit,
|
||||
ULONG flags
|
||||
)
|
||||
{
|
||||
int retval = FALSE;
|
||||
|
||||
/* Enforce single threading so we can Wait() */
|
||||
ObtainSemaphore(LIBBASE->nid_Lock);
|
||||
if (unit >= NETINFO_UNITS)
|
||||
goto zap;
|
||||
|
||||
/*
|
||||
* Create device task if necessary
|
||||
*/
|
||||
while (LIBBASE->nid_Task == NULL) {
|
||||
struct MsgPort *mp;
|
||||
struct Message *msg;
|
||||
struct Process *task;
|
||||
|
||||
LIBBASE->nid_DOSBase = OpenLibrary("dos.library",37L);
|
||||
if (LIBBASE->nid_DOSBase == NULL)
|
||||
break;
|
||||
|
||||
mp = CreateMsgPort();
|
||||
if (mp == NULL)
|
||||
break;
|
||||
msg = CreateIORequest(mp, sizeof(*msg));
|
||||
if (msg) {
|
||||
/* Create new process, wait for the message */
|
||||
msg->mn_Node.ln_Type = NT_MESSAGE;
|
||||
msg->mn_Node.ln_Name = (void *)LIBBASE;
|
||||
task = CreateNewProcTags(NP_Entry, NetInfoStartup,
|
||||
NP_Priority, NID_PRIORITY,
|
||||
NP_Name, MOD_NAME_STRING,
|
||||
NP_ExitData, msg,
|
||||
TAG_END);
|
||||
do {
|
||||
Wait(1L << mp->mp_SigBit);
|
||||
} while (GetMsg(mp) != msg);
|
||||
|
||||
DeleteIORequest(msg);
|
||||
}
|
||||
DeleteMsgPort(mp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (LIBBASE->nid_Task == NULL)
|
||||
goto zap;
|
||||
|
||||
/* OK, create a new unit structure, fill in a request and return */
|
||||
req->io_Device = (struct Device *) LIBBASE;
|
||||
if (req->io_Unit = CreateNewUnit(LIBBASE, unit)) {
|
||||
retval = TRUE;
|
||||
}
|
||||
zap:
|
||||
if (req->io_Error = retval) {
|
||||
req->io_Unit = (struct Unit *) -1;
|
||||
req->io_Device = (struct Device *) -1;
|
||||
}
|
||||
|
||||
ReleaseSemaphore(LIBBASE->nid_Lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int NetInfo__DevClose(LIBBASETYPEPTR LIBBASE,
|
||||
struct IORequest *req
|
||||
)
|
||||
{
|
||||
int retval = FALSE;
|
||||
|
||||
ObtainSemaphore(LIBBASE->nid_Lock);
|
||||
{
|
||||
ExpungeUnit(LIBBASE, req->io_Unit);
|
||||
retval = TRUE;
|
||||
}
|
||||
ReleaseSemaphore(LIBBASE->nid_Lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device expunge
|
||||
*/
|
||||
static int NetInfo__DevExpunge(LIBBASETYPEPTR LIBBASE)
|
||||
{
|
||||
if (AttemptSemaphore(LIBBASE->nid_Lock)) {
|
||||
if (LIBBASE->nid_Task) {
|
||||
if (LIBBASE->nid_Death && LIBBASE->nid_Death->mn_Node.ln_Type == NT_MESSAGE)
|
||||
ReplyMsg(LIBBASE->nid_Death);
|
||||
}
|
||||
ReleaseSemaphore(LIBBASE->nid_Lock);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ADD2OPENDEV(NetInfo__DevOpen, 0)
|
||||
ADD2CLOSEDEV(NetInfo__DevClose, 0)
|
||||
|
||||
ADD2INITLIB(NetInfo__DevInit, 0)
|
||||
ADD2EXPUNGELIB(NetInfo__DevExpunge, 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Queue requests
|
||||
*/
|
||||
#define IMMEDIATE_CMDS 0L
|
||||
AROS_LH1(void, BeginIO,
|
||||
AROS_LHA(struct NetInfoReq *, req, A1),
|
||||
struct NetInfoDevice *, nid, 5, NetInfo)
|
||||
{
|
||||
AROS_LIBFUNC_INIT
|
||||
|
||||
req->io_Message.mn_Node.ln_Type = NT_MESSAGE;
|
||||
|
||||
if (req->io_Command >= NI_END) {
|
||||
req->io_Error = IOERR_NOCMD;
|
||||
TermIO(req);
|
||||
#if IMMEDIATE_CMDS
|
||||
} else if ((req->io_Flags & IOF_QUICK) &&
|
||||
(1L << req->io_Command) & IMMEDIATE_CMDS) {
|
||||
PerformIO(nid, req);
|
||||
#endif
|
||||
} else {
|
||||
req->io_Flags &= ~IOF_QUICK;
|
||||
PutMsg(nid->nid_Port, (struct Message *)req);
|
||||
}
|
||||
|
||||
AROS_LIBFUNC_EXIT
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The device AbortIO() entry point.
|
||||
*
|
||||
* A1 - The IO request to be aborted.
|
||||
* A6 - The device base.
|
||||
*/
|
||||
AROS_LH1(LONG, AbortIO,
|
||||
AROS_LHA(struct NetInfoReq *, ni, A1),
|
||||
struct NetInfoDevice *, nid, 6, NetInfo)
|
||||
{
|
||||
AROS_LIBFUNC_INIT
|
||||
|
||||
ULONG result = 0L;
|
||||
struct NetInfoMap *nim;
|
||||
|
||||
if (ni->io_Unit == NULL)
|
||||
return NIERR_NULL_POINTER;
|
||||
|
||||
nim = CheckUnit(nid, ni->io_Unit);
|
||||
if (nim == NULL)
|
||||
return IOERR_BADADDRESS;
|
||||
|
||||
ObtainSemaphore(nim->nim_ReqLock);
|
||||
|
||||
if (ni->io_Message.mn_Node.ln_Type != NT_REPLYMSG) {
|
||||
switch (ni->io_Command) {
|
||||
case CMD_READ:
|
||||
result = AbortReq(nid, nim->nim_Rx, ni);
|
||||
break;
|
||||
case CMD_WRITE:
|
||||
result = AbortReq(nid, nim->nim_Wx, ni);
|
||||
break;
|
||||
default:
|
||||
result = IOERR_NOCMD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSemaphore(nim->nim_ReqLock);
|
||||
|
||||
return(result);
|
||||
|
||||
AROS_LIBFUNC_EXIT
|
||||
}
|
||||
11
workbench/devs/netinfo/netinfo.conf
Normal file
11
workbench/devs/netinfo/netinfo.conf
Normal file
@ -0,0 +1,11 @@
|
||||
##begin config
|
||||
version 44.0
|
||||
basename NetInfo
|
||||
libbasetype struct NetInfoDevice
|
||||
residentpri 0
|
||||
beginio_func BeginIO
|
||||
abortio_func AbortIO
|
||||
##end config
|
||||
##begin cdefprivate
|
||||
#include "base.h"
|
||||
##end cdefprivate
|
||||
300
workbench/devs/netinfo/passwdunit.c
Normal file
300
workbench/devs/netinfo/passwdunit.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* passwdunit.c --- unit for passwd entries
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
|
||||
#include "entries.h"
|
||||
#include <string.h>
|
||||
#if defined(DEBUG)
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
static void *CopyEntToPasswd(struct NetInfoReq *req, struct Ent *e);
|
||||
static struct Ent *CopyPasswdToEnt(struct NetInfoDevice *nid, struct NetInfoReq *req);
|
||||
static struct Ent *ParsePasswd(struct NetInfoDevice *nid, register UBYTE *p);
|
||||
static void GetMembers(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim);
|
||||
static int PrintPasswd(struct NetInfoDevice *nid, BPTR file, struct Ent *e);
|
||||
|
||||
const static struct MapMethods passwd_methods[1] = {
|
||||
{
|
||||
ParsePasswd,
|
||||
PrintPasswd,
|
||||
CopyEntToPasswd,
|
||||
CopyPasswdToEnt,
|
||||
EntCleanup,
|
||||
NULL,
|
||||
EntHandleNotify,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate and initialize passwd map
|
||||
*/
|
||||
struct NetInfoMap *InitPasswdMap(struct NetInfoDevice *nid)
|
||||
{
|
||||
struct NetInfoMap *nim = AllocVec(sizeof(*nim), MEMF_CLEAR|MEMF_PUBLIC);
|
||||
|
||||
if (nim) {
|
||||
nim->nim_Methods = passwd_methods;
|
||||
nim->nim_Name = "passwd";
|
||||
nim->nim_Filename = _PATH_PASSWD;
|
||||
}
|
||||
|
||||
return nim;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an PasswdEnt structure to passwd structure
|
||||
*/
|
||||
static void *CopyEntToPasswd(struct NetInfoReq *req, struct Ent *e)
|
||||
{
|
||||
struct PasswdEnt *pe = (struct PasswdEnt *)e;
|
||||
struct NetInfoPasswd *pw = req->io_Data;
|
||||
UBYTE *to = (UBYTE *)(pw + 1);
|
||||
|
||||
ULONG size = req->io_Length;
|
||||
ULONG actual = sizeof(*pw) + pe->pe_tlen;
|
||||
|
||||
req->io_Actual = actual;
|
||||
|
||||
if (size < actual) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* copy strings */
|
||||
to = stpcopy(pw->pw_name = to, pe->pe_passwd->pw_name);
|
||||
to = stpcopy(pw->pw_passwd = to, pe->pe_passwd->pw_passwd);
|
||||
to = stpcopy(pw->pw_gecos = to, pe->pe_passwd->pw_gecos);
|
||||
to = stpcopy(pw->pw_dir = to, pe->pe_passwd->pw_dir);
|
||||
to = stpcopy(pw->pw_shell = to, pe->pe_passwd->pw_shell);
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(to == (UBYTE *)req->io_Data + actual);
|
||||
#endif
|
||||
/* .. and ids */
|
||||
pw->pw_uid = pe->pe_passwd->pw_uid;
|
||||
pw->pw_gid = pe->pe_passwd->pw_gid;
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an passwd structure into a internal entry
|
||||
*/
|
||||
static struct Ent *CopyPasswdToEnt(struct NetInfoDevice *nid, struct NetInfoReq *req)
|
||||
{
|
||||
struct NetInfoPasswd *pw = (struct NetInfoPasswd*)req->io_Data;
|
||||
struct PasswdEnt *pe;
|
||||
UBYTE *to;
|
||||
ULONG txtlen;
|
||||
|
||||
/*
|
||||
* These cause EFAULT
|
||||
*/
|
||||
if (pw == NULL || (1 & (IPTR)pw) != 0 ||
|
||||
pw->pw_name == NULL ||
|
||||
pw->pw_passwd == NULL ||
|
||||
pw->pw_gecos == NULL ||
|
||||
pw->pw_dir == NULL ||
|
||||
pw->pw_shell == NULL) {
|
||||
req->io_Error = IOERR_BADADDRESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
txtlen = strlen(pw->pw_name) + strlen(pw->pw_passwd) + strlen(pw->pw_gecos) +
|
||||
strlen(pw->pw_dir) + strlen(pw->pw_shell) + 5;
|
||||
|
||||
pe = AllocVec(sizeof(*pe) + txtlen, MEMF_CLEAR);
|
||||
if (pe == NULL) {
|
||||
req->io_Error = NIERR_NOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pe->pe_node.ln_Type = ENT_PASSWD;
|
||||
pe->pe_node.ln_Pri = ENT_CHANGED;
|
||||
pe->pe_tlen = txtlen;
|
||||
pe->pe_passwd->pw_uid = pw->pw_uid;
|
||||
pe->pe_passwd->pw_gid = pw->pw_gid;
|
||||
|
||||
to = (UBYTE *)(pe + 1);
|
||||
to = stpcopy(pe->pe_passwd->pw_name = to, pw->pw_name);
|
||||
to = stpcopy(pe->pe_passwd->pw_passwd = to, pw->pw_passwd);
|
||||
to = stpcopy(pe->pe_passwd->pw_gecos = to, pw->pw_gecos);
|
||||
to = stpcopy(pe->pe_passwd->pw_dir = to, pw->pw_dir);
|
||||
to = stpcopy(pe->pe_passwd->pw_shell = to, pw->pw_shell);
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(to == pe->pe_passwd->pw_name + txtlen);
|
||||
#endif
|
||||
return (struct Ent *)pe;
|
||||
}
|
||||
|
||||
/****** netinfo.device/passwd **********************************************
|
||||
|
||||
NAME
|
||||
passwd - format of the password file
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The passwd files are files consisting of newline separated records,
|
||||
one per user, containing seven bar (`|') separated fields. These
|
||||
fields are as follows:
|
||||
|
||||
name User's login name.
|
||||
|
||||
password User's encrypted password.
|
||||
|
||||
uid User's id.
|
||||
|
||||
gid User's login group id.
|
||||
|
||||
gecos General information about the user.
|
||||
|
||||
home_dir User's home directory.
|
||||
|
||||
shell User's login shell.
|
||||
|
||||
The name field is the login used to access the computer account, and
|
||||
the uid field is the number associated with it. They should both be
|
||||
unique across the system (and often across a group of systems) since
|
||||
they control file access.
|
||||
|
||||
While it is possible to have multiple entries with identical login
|
||||
names and/or identical user id's, it is usually a mistake to do so.
|
||||
Routines that manipulate these files will often return only one of
|
||||
the multiple entries, and that one by random selection.
|
||||
|
||||
The login name must never begin with a hyphen (`-'); also, it is
|
||||
strongly suggested that neither upper-case characters or dots (`.')
|
||||
be part of the name, as this tends to confuse mailers. No field may
|
||||
contain a bar (`|') as this has been used to separate the fields in
|
||||
the user database.
|
||||
|
||||
The password field is the encrypted form of the password. The actual
|
||||
format is not restricted by netinfo.device, but usergroup.library
|
||||
uses same format as Version 7 UNIX (POSIX) or 4.4BSD. The format
|
||||
used by MultiUser 1.5 or AS225r2<72> is also possible, but its use is
|
||||
strongly discouraged.
|
||||
|
||||
If the password field is empty, no password will be required to gain
|
||||
access to the machine. This is almost invariably a mistake. Because
|
||||
these files contain the encrypted user passwords, they should not be
|
||||
readable by anyone without appropriate privileges.
|
||||
|
||||
The group field is the group that the user will be placed in upon
|
||||
login.
|
||||
|
||||
The gecos field normally contains comma (`,') separated subfields as
|
||||
follows:
|
||||
|
||||
name user's full name
|
||||
office user's office number
|
||||
wphone user's work phone number
|
||||
hphone user's home phone number
|
||||
|
||||
This information is used by the finger program.
|
||||
|
||||
The user's home directory is the full DOS path name where the user
|
||||
will be placed on login.
|
||||
|
||||
The shell field is the command interpreter the user prefers. If
|
||||
there is nothing in the shell field, the CLI is assumed.
|
||||
|
||||
FILES
|
||||
AmiTCP:db/passwd
|
||||
|
||||
SEE ALSO
|
||||
group
|
||||
|
||||
COPYRIGHT
|
||||
Copyright 1980, 1991 The Regents of the University of California.
|
||||
Copyright 1993, 1994 AmiTCP/IP-Group, <AmiTCP-Group@hut.fi>,
|
||||
Helsinki University of Technology, Helsinki
|
||||
|
||||
HISTORY
|
||||
A passwd file format appeared in Version 6 AT&T UNIX.
|
||||
|
||||
The used format is basically the same as in the Multiuser Library
|
||||
1.3 and AS225r2 use, except the password field.
|
||||
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Parse a passwd database entry
|
||||
*/
|
||||
static struct Ent *ParsePasswd(struct NetInfoDevice *nid, register UBYTE *p)
|
||||
{
|
||||
int i;
|
||||
UBYTE *to, *np = p, *field[PASSWDFIELDS];
|
||||
ULONG txtlen;
|
||||
LONG uid, gid;
|
||||
struct PasswdEnt *pe;
|
||||
|
||||
for (i = 0;
|
||||
i < PASSWDFIELDS && (field[i++] = strsep((char **)&np, "|\n")) && np && *np;)
|
||||
;
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(np != NULL);
|
||||
#endif
|
||||
if (i < PASSWDFIELDS || !np) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((i = StrToLong(field[2], &uid)) <= 0 || field[2][i] != '\0')
|
||||
return NULL;
|
||||
if ((i = StrToLong(field[3], &gid)) <= 0 || field[3][i] != '\0')
|
||||
return NULL;
|
||||
|
||||
txtlen = np - field[0] - (field[4] - field[2]);
|
||||
pe = AllocVec(sizeof(*pe) + txtlen, MEMF_CLEAR);
|
||||
if (!pe)
|
||||
return NULL;
|
||||
|
||||
pe->pe_node.ln_Type = ENT_PASSWD;
|
||||
pe->pe_tlen = txtlen;
|
||||
pe->pe_passwd->pw_uid = uid;
|
||||
pe->pe_passwd->pw_gid = gid;
|
||||
|
||||
to = (UBYTE *)(pe + 1);
|
||||
to = stpcopy(pe->pe_passwd->pw_name = to, field[0]);
|
||||
to = stpcopy(pe->pe_passwd->pw_passwd = to, field[1]);
|
||||
to = stpcopy(pe->pe_passwd->pw_gecos = to, field[4]);
|
||||
to = stpcopy(pe->pe_passwd->pw_dir = to, field[5]);
|
||||
to = stpcopy(pe->pe_passwd->pw_shell = to, field[6]);
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(to == pe->pe_passwd->pw_name + txtlen);
|
||||
#endif
|
||||
return (struct Ent *)pe;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out an passwd entry
|
||||
*/
|
||||
static int PrintPasswd(struct NetInfoDevice *nid, BPTR file, struct Ent *e)
|
||||
{
|
||||
struct PasswdEnt *pe = (struct PasswdEnt *)e;
|
||||
|
||||
if (VFPrintf(file, "%s|%s|%ld|%ld|%s|%s|%s\n", (RAWARG)pe->pe_passwd) == -1)
|
||||
return NIERR_ACCESS;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all UIDs in the named group
|
||||
*/
|
||||
static void GetMembers(struct NetInfoDevice *nid, struct NetInfoReq *req, struct NetInfoMap *nim)
|
||||
{
|
||||
req->io_Error = NIERR_NOTFOUND;
|
||||
TermIO(req);
|
||||
}
|
||||
245
workbench/devs/netinfo/server.c
Normal file
245
workbench/devs/netinfo/server.c
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* server.c -- Netinfo Server Process
|
||||
*
|
||||
* Author: ppessi <Pekka.Pessi@hut.fi>
|
||||
*
|
||||
* Copyright <20> 1993 AmiTCP/IP Group, <AmiTCP-group@hut.fi>
|
||||
* Helsinki University of Technology, Finland.
|
||||
*/
|
||||
|
||||
#include <proto/exec.h>
|
||||
|
||||
#include "base.h"
|
||||
#include "assert.h"
|
||||
|
||||
static void NetInfoPoll(struct NetInfoDevice *nid);
|
||||
|
||||
/*
|
||||
* Task Startup routine
|
||||
* This is called from DOS, so it has got no devbase
|
||||
*/
|
||||
#if !defined(__AROS__)
|
||||
#undef SysBase
|
||||
#define SysBase (*(APTR *)4)
|
||||
#endif
|
||||
|
||||
SAVEDS ASM LONG NetInfoStartup(void)
|
||||
{
|
||||
struct NetInfoDevice *dev;
|
||||
struct Message *ok_message = (struct Message *)
|
||||
((struct Process*)FindTask(NULL))->pr_ExitData;
|
||||
|
||||
if (ok_message) {
|
||||
dev = (struct NetInfoDevice *) ok_message->mn_Node.ln_Name;
|
||||
if (dev) {
|
||||
NetInfoTask(dev, ok_message);
|
||||
} else {
|
||||
Forbid();
|
||||
ReplyMsg(ok_message);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TermIO(struct NetInfoReq *req)
|
||||
{
|
||||
if ((req->io_Flags & IOF_QUICK) == 0)
|
||||
ReplyMsg((struct Message *)req);
|
||||
}
|
||||
#if !defined(__AROS__)
|
||||
#undef SysBase
|
||||
#define SysBase (nid->nid_ExecBase)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialize device port
|
||||
*/
|
||||
void NetInfoTask(struct NetInfoDevice *nid, struct Message *ok_message)
|
||||
{
|
||||
BYTE ps = AllocSignal(-1);
|
||||
struct Message *death;
|
||||
|
||||
/* Create main message port */
|
||||
if (ps != -1) {
|
||||
|
||||
/* Mr. Death */
|
||||
if (death = CreateIORequest(nid->nid_Port, sizeof(*death))) {
|
||||
struct NetInfoMap *maps[NETINFO_UNITS];
|
||||
struct NetInfoMap *mapp;
|
||||
short map;
|
||||
|
||||
for (map = NETINFO_PASSWD_UNIT; map < NETINFO_UNITS; map++) {
|
||||
mapp = maps[map] = InitNetInfoMap(nid, nid->nid_Port, map);
|
||||
if (!mapp)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If everything went well */
|
||||
if (map == NETINFO_UNITS) {
|
||||
/* Init ports */
|
||||
nid->nid_Port->mp_Flags = PA_SIGNAL;
|
||||
nid->nid_Port->mp_SigBit = ps;
|
||||
nid->nid_Port->mp_SigTask = FindTask(NULL);
|
||||
InitList(&nid->nid_Port->mp_MsgList);
|
||||
|
||||
nid->nid_NotifyPort->mp_Flags = PA_SIGNAL;
|
||||
nid->nid_NotifyPort->mp_SigBit = ps;
|
||||
nid->nid_NotifyPort->mp_SigTask = FindTask(NULL);
|
||||
InitList(&nid->nid_NotifyPort->mp_MsgList);
|
||||
|
||||
death->mn_Node.ln_Type = NT_MESSAGE;
|
||||
nid->nid_Death = death;
|
||||
for (map = NETINFO_PASSWD_UNIT; map < NETINFO_UNITS; map++)
|
||||
nid->nid_Maps[map] = maps[map];
|
||||
|
||||
ReplyMsg(ok_message);
|
||||
|
||||
NetInfoPoll(nid);
|
||||
return;
|
||||
} else {
|
||||
while (map > 0) {
|
||||
DeInitNetInfoMap(nid, maps[map--]);
|
||||
}
|
||||
}
|
||||
DeleteIORequest(death);
|
||||
}
|
||||
FreeSignal(ps);
|
||||
}
|
||||
|
||||
ok_message->mn_Node.ln_Name = NULL;
|
||||
ReplyMsg(ok_message);
|
||||
}
|
||||
|
||||
static void NetInfoPoll(struct NetInfoDevice *nid)
|
||||
{
|
||||
ULONG mask = 1L << nid->nid_Port->mp_SigBit;
|
||||
|
||||
while (mask) {
|
||||
struct NetInfoReq *req;
|
||||
struct NotifyMessage *notify;
|
||||
|
||||
Wait(mask);
|
||||
|
||||
while (req = (struct NetInfoReq *)GetMsg(nid->nid_Port)) {
|
||||
if (nid->nid_Death == &req->io_Message)
|
||||
mask = 0;
|
||||
else
|
||||
PerformIO(nid, req);
|
||||
}
|
||||
|
||||
while (notify = (struct NotifyMessage *)GetMsg(nid->nid_NotifyPort)) {
|
||||
struct NetInfoMap *nim = (void *)notify->nm_NReq->nr_UserData;
|
||||
|
||||
ReplyMsg((struct Message *)notify);
|
||||
|
||||
if (nim != NULL) {
|
||||
Method(notify, nim)(nid, nim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/*
|
||||
* Free all allocated resources when die
|
||||
*/
|
||||
struct NetInfoMap *mapp;
|
||||
short map;
|
||||
|
||||
ObtainSemaphore(nid->nid_Lock);
|
||||
|
||||
for (map = NETINFO_PASSWD_UNIT; map < NETINFO_UNITS; map++) {
|
||||
if (mapp = nid->nid_Maps[map])
|
||||
DeInitNetInfoMap(nid, mapp);
|
||||
nid->nid_Maps[map] = NULL;
|
||||
}
|
||||
|
||||
if (nid->nid_SigBit != -1)
|
||||
FreeSignal(nid->nid_SigBit), nid->nid_SigBit = (UBYTE)-1;
|
||||
|
||||
if (nid->nid_Death)
|
||||
DeleteIORequest(nid->nid_Death), nid->nid_Death = NULL;
|
||||
|
||||
nid->nid_Task = NULL;
|
||||
|
||||
ReleaseSemaphore(nid->nid_Lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create netinfo pointer
|
||||
*/
|
||||
struct Unit *CreateNewUnit(struct NetInfoDevice *nid, short unit)
|
||||
{
|
||||
struct NetInfoMap *nim = nid->nid_Maps[unit];
|
||||
struct NetInfoPointer *nip = AllocVec(sizeof(*nip), MEMF_CLEAR);
|
||||
|
||||
if (nip) {
|
||||
nim->nim_OpenCnt++;
|
||||
nip->nip_Name = nim->nim_Name;
|
||||
nip->nip_UnitNumber = unit;
|
||||
nip->nip_Map = nim;
|
||||
nip->nip_Ent = NULL;
|
||||
ObtainSemaphore(nim->nim_PointerLock);
|
||||
AddHead(nim->nim_Pointer, nip->nip_Node);
|
||||
ReleaseSemaphore(nim->nim_PointerLock);
|
||||
}
|
||||
|
||||
return (struct Unit *)nip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete netinfo pointer
|
||||
*/
|
||||
void ExpungeUnit(struct NetInfoDevice *nid, struct Unit *u)
|
||||
{
|
||||
struct NetInfoPointer *nip = (struct NetInfoPointer *)u;
|
||||
struct NetInfoMap *nim = CheckUnit(nid, u);
|
||||
|
||||
if (nim == NULL) {
|
||||
/* We should do an Alert */
|
||||
InMsg("CloseDevice(): illegal unit pointer %lx", u);
|
||||
} else {
|
||||
ObtainSemaphore(nim->nim_PointerLock);
|
||||
nim->nim_OpenCnt--;
|
||||
Remove(nip->nip_Node);
|
||||
ReleaseSemaphore(nim->nim_PointerLock);
|
||||
FreeVec(nip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void PerformIO(struct NetInfoDevice *nid, struct NetInfoReq *req)
|
||||
{
|
||||
struct NetInfoMap *nim = CheckUnit(nid, req->io_Unit);
|
||||
|
||||
if (nim) {
|
||||
DoNIMethod(req->io_Command, req, nim);
|
||||
} else {
|
||||
req->io_Error = IOERR_BADADDRESS;
|
||||
TermIO(req);
|
||||
}
|
||||
}
|
||||
|
||||
ULONG AbortReq(struct NetInfoDevice *nid, struct List *l, struct NetInfoReq *req)
|
||||
{
|
||||
struct Node *n;
|
||||
|
||||
for (n = l->lh_Head; n->ln_Succ; n = n->ln_Succ) {
|
||||
if (n == (struct Node *)req) {
|
||||
Remove((struct Node *)req);
|
||||
req->io_Error = IOERR_ABORTED;
|
||||
TermIO(req);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return IOERR_NOCMD;
|
||||
}
|
||||
|
||||
void UnknownCommand(struct NetInfoDevice *nid, struct NetInfoReq * req, struct NetInfoMap *nim)
|
||||
{
|
||||
req->io_Error = IOERR_NOCMD;
|
||||
TermIO(req);
|
||||
}
|
||||
Reference in New Issue
Block a user