1
0
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:
Kalamatee
2025-10-03 22:41:19 +01:00
committed by deadwood
parent 998720f54b
commit e8b8e5c937
13 changed files with 2088 additions and 0 deletions

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

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

View 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

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

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

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

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

View 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

View 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
}

View 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

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

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