mars-nwe/ncpserv.c

1351 lines
47 KiB
C

/* ncpserv.c, 22-Nov-95 */
/* (C)opyright (C) 1993,1995 Martin Stover, Marburg, Germany
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "net.h"
#include "nwdbm.h"
int conn_gid;
int conn_uid;
int nwconn_debug=0;
int ipxdebug=0;
static int ncp_fd = -1;
static uint8 ipx_in_data[IPX_MAX_DATA+500]; /* space for additional data */
static NCPREQUEST *ncprequest = (NCPREQUEST*)&ipx_in_data;
static struct t_unitdata ud;
static int in_len=0;
static uint8 ipx_pack_typ=17;
static ipxAddr_t from_addr; /* aktuelle Anforderungsaddresse */
static ipxAddr_t my_addr;
static int rcv_flags = 0;
static char my_nwname[50];
static time_t akttime;
static void write_to_nwserv(int what, int connection, char *data, int size)
{
switch (what) {
case 0x2222 : /* insert wdog connection */
write(FD_NWSERV, &what, sizeof(int));
write(FD_NWSERV, &connection, sizeof(int));
write(FD_NWSERV, data, size); /* ipxAddr_t */
break;
case 0x4444 : /* tell the wdog there's no need to look */
case 0x6666 : /* the connection ist closed */
case 0x8888 : /* send to client that server holds message */
write(FD_NWSERV, &what, sizeof(int));
write(FD_NWSERV, &connection, sizeof(int));
break;
default : break;
}
}
static int open_ncp_socket()
{
struct t_bind bind;
ncp_fd=t_open("/dev/ipx", O_RDWR, NULL);
if (ncp_fd < 0) {
t_error("t_open !Ok");
return(-1);
}
U16_TO_BE16(SOCK_NCP, my_addr.sock); /* NCP_SOCKET */
bind.addr.len = sizeof(ipxAddr_t);
bind.addr.maxlen = sizeof(ipxAddr_t);
bind.addr.buf = (char*)&my_addr;
bind.qlen = 0; /* immer */
if (t_bind(ncp_fd, &bind, &bind) < 0){
t_error("t_bind in open_ncp_socket !OK");
close(ncp_fd);
return(-1);
}
return(0);
}
typedef struct {
int fd; /* writepipe */
int pid; /* pid from son */
ipxAddr_t client_adr; /* address client */
uint32 object_id; /* logged object */
/* 0 = not logged in */
uint8 crypt_key[8]; /* password generierung */
uint8 message[60]; /* saved BCastmessage */
int sequence; /* previous sequence */
int retry; /* one reply being serviced is sent */
time_t last_access; /* time of last 0x2222 request */
time_t t_login; /* login time */
} CONNECTION;
static CONNECTION connections[MAX_CONNECTIONS];
static int anz_connect=0; /* aktuelle Connections */
static int new_conn_nr(void)
{
int j = -1;
if (!anz_connect){ /* alles initialisieren */
j = MAX_CONNECTIONS;
while (j--) {
connections[j].fd = -1;
connections[j].message[0] = '\0';
}
anz_connect++;
return(1);
}
j = -1;
while (++j < MAX_CONNECTIONS) {
if (connections[j].fd < 0) {
connections[j].message[0] = '\0';
if (++j > anz_connect) anz_connect=j;
return(j);
}
}
return(0); /* nichts frei */
}
int free_conn_nr(int nr)
{
if (nr && --nr < anz_connect) {
connections[nr].fd = -1;
return(0);
}
return(-1);
}
int find_conn_nr(ipxAddr_t *addr)
{
int j = -1;
while (++j < anz_connect) {
if (connections[j].fd > -1 &&
!memcmp((char*)&(connections[j].client_adr),
(char*)addr, sizeof(ipxAddr_t))) return(++j);
}
return(0);
}
void clear_connection(int conn)
{
write_to_nwserv(0x6666, conn, NULL, 0);
if (conn > 0 && --conn < anz_connect) {
CONNECTION *c = &connections[conn];
if (c->fd > -1) {
close(c->fd);
c->fd = -1;
if (c->pid > -1) {
kill(c->pid, SIGTERM); /* hier nochmal's killen */
c->pid = -1;
}
}
c->object_id = 0;
conn = anz_connect;
while (conn--) {
CONNECTION *c = &connections[conn];
if (c->fd < 0) anz_connect--;
else break;
}
}
}
int find_get_conn_nr(ipxAddr_t *addr)
{
int connection=find_conn_nr(addr);
if (!connection){
if ((connection = new_conn_nr()) > 0){
CONNECTION *c=&(connections[connection-1]);
int fds[2];
memcpy((char*) &(c->client_adr), (char *)addr, sizeof(ipxAddr_t));
if (pipe(fds) < 0) {
perror("find_get_conn_nr, pipe");
free_conn_nr(connection);
return(0);
} else {
int akt_pid = getpid();
int pid = fork();
if (pid < 0) {
perror("find_get_conn_nr, fork");
free_conn_nr(connection);
close(fds[0]);
close(fds[1]);
return(0);
}
if (pid == 0) {
/* new process */
char *progname="nwconn";
char pathname[300];
char pidstr[20];
char connstr[20];
char addrstr[100];
char gidstr[10];
char uidstr[10];
char db_str1[5];
char db_str2[5];
int j = 2;
close(fds[1]); /* no writing */
dup2(fds[0], 0); /* becomes stdin */
close(fds[0]); /* not needed */
while (j++ < 100) close(j); /* close all > stderr */
sprintf(pidstr, "%d", akt_pid);
sprintf(connstr, "%d", connection);
sprintf(gidstr, "%d", conn_gid);
sprintf(uidstr, "%d", conn_uid);
sprintf(db_str1, "%d", nwconn_debug);
sprintf(db_str2, "%d", ipxdebug);
ipx_addr_to_adr(addrstr, addr);
execl(get_exec_path(pathname, progname), progname,
pidstr, addrstr, connstr,
gidstr, uidstr,
db_str1,
db_str2, NULL);
exit(1); /* normaly not reached */
}
c->pid = pid;
c->fd = fds[1];
close(fds[0]); /* no need to read */
XDPRINTF((5, "AFTER FORK new PROCESS =%d, connection=%d\n", pid, connection));
}
}
}
if (connection) write_to_nwserv(0x2222, connection, (char*)addr, sizeof(ipxAddr_t));
return(connection);
}
static void get_login_time(uint8 login_time[], CONNECTION *cx)
{
struct tm *s_tm = localtime(&(cx->t_login));
login_time[0] = s_tm->tm_year;
login_time[1] = s_tm->tm_mon+1;
login_time[2] = s_tm->tm_mday;
login_time[3] = s_tm->tm_hour;
login_time[4] = s_tm->tm_min;
login_time[5] = s_tm->tm_sec;
login_time[6] = s_tm->tm_wday;
}
static int handle_fxx(CONNECTION *c, int gelen, int func)
/* here are handled the global 0x15, 0x17 functions */
{
IPX_DATA ipxoutdata;
NCPRESPONSE *ncpresponse = (NCPRESPONSE*)&ipxoutdata;
uint8 *responsedata = ((uint8*)&ipxoutdata)+sizeof(NCPRESPONSE);
uint8 *requestdata = ((uint8*)ncprequest)+sizeof(NCPREQUEST);
uint8 len = *(requestdata+1);
uint8 ufunc = *(requestdata+2);
uint8 *rdata = requestdata+3;
uint8 completition = 0;
uint8 connect_status= 0;
int data_len = 0;
if (nw_debug){
int j = gelen - sizeof(NCPREQUEST);
if (nw_debug){
DPRINTF(("NCP 0x%x REQUEST:ufunc:0x%x\n", func, ufunc));
if (j > 0){
uint8 *p=requestdata;
DPRINTF(("len %d, DATA:", j));
while (j--) {
int c = *p++;
if (c > 32 && c < 127) DPRINTF((",\'%c\'", (char) c));
else DPRINTF((",0x%x", c));
}
DPRINTF(("\n"));
}
}
}
if (0x15 == func) {
switch (ufunc) { /* Messages */
case 0x0 : { /* Send Broadcast Message (old) */
int anz_conns = (int)*(rdata); /* Number of connections */
uint8 *conns = rdata+1; /* connectionslist */
int msglen = *(conns+anz_conns);
uint8 *msg = conns+anz_conns+1;
uint8 *p = responsedata;
int one_found = 0;
int k = -1;
*p++ = (uint8) anz_conns;
while (++k < anz_conns) {
int connr = (int) (*conns++);
int result = 0xff; /* target not ok */
CONNECTION *cn;
if (connr > 0 && --connr < anz_connect
&& ((cn = &connections[connr]))->fd > -1 ) {
if (!cn->message[0]) {
strmaxcpy(cn->message, msg, min(58, msglen));
result = 0; /* Ok */
} else result = 0xfc; /* server holds message */
write_to_nwserv(0x8888, connr+1, NULL, 0);
one_found++;
}
*p++ = (uint8)result;
}
if (one_found) data_len = anz_conns+1;
else completition=0xff;
}
break;
case 0x01: { /* Get Broadcast Message (old) */
*responsedata = (uint8) strmaxcpy(responsedata+1, c->message, 58);
c->message[0] = '\0';
data_len = (int)(*responsedata) + 1;
}
break;
case 0x03: { /* Enable Broadcasts */
;;;
DPRINTF(("TODO: enable Broadcasts\n"));
}
break;
case 0x09: { /* Broadcast to CONSOLE */
char message[60];
strmaxcpy(message, rdata+1, min(59, *rdata));
fprintf(stderr, "\n:%s\n", message);
}
break;
case 0xa: /* Send Broadcast Message (new) */
case 0xb: /* Get Broadcast Message (new) */
default : return(-1); /* not handled */
} /* switch */
} else if (0x17 == func) { /* Fileserver Enviro */
switch (ufunc) {
case 0x01 : { /* Change User Password OLD */
completition=0xff;
}
break;
case 0x0c : { /* Verify Serialization */
completition=0xff;
}
break;
case 0x0e : { /* Get Disk Utilization */
completition=0xff;
}
break;
case 0x11 : { /* Get FileServer Info */
struct XDATA {
uint8 servername[48];
uint8 version; /* 3 */
uint8 subversion; /* 11 */
uint8 maxconnections[2];
uint8 connection_in_use[2];
uint8 max_volumes[2];
uint8 os_revision;
uint8 sft_level;
uint8 tts_level;
uint8 peak_connection[2];
uint8 accounting_version;
uint8 vap_version;
uint8 queuing_version;
uint8 print_server_version;
uint8 virtual_console_version;
uint8 security_level;
uint8 internet_bridge_version;
uint8 reserved[60];
} *xdata = (struct XDATA*) responsedata;
memset(xdata, 0, sizeof(struct XDATA));
strcpy(xdata->servername, my_nwname);
xdata->version = 3;
xdata->subversion = 11;
U16_TO_BE16(MAX_CONNECTIONS, xdata->maxconnections);
U16_TO_BE16(anz_connect, xdata->connection_in_use);
U16_TO_BE16(MAX_NW_VOLS, xdata->max_volumes);
data_len = sizeof(struct XDATA);
} break;
case 0x12 : { /* Get Network Serial Number */
struct XDATA {
uint8 serial_number[4];
uint8 appl_number[2];
} *xdata = (struct XDATA*) responsedata;
/* serial-number 4-Byte */
U32_TO_BE32(0x44444444, xdata->serial_number);
/* applikation-number 2-Byte */
U16_TO_BE16(0x2222, xdata->appl_number);
data_len = sizeof(struct XDATA);
}
break;
case 0x13 : { /* Get Connection Internet Address */
int conn = (int)*(rdata); /* Connection Nr */
if (conn && --conn < anz_connect
&& connections[conn].fd > -1 ) {
CONNECTION *cx=&(connections[conn]);
data_len = sizeof(ipxAddr_t);
memcpy(responsedata, (char*)&(cx->client_adr), data_len);
} else completition = 0xff;
} break;
case 0x14 : { /* Login Objekt, unencrypted passwords */
uint8 *p = rdata;
uint8 *p1 = p+3 + *(p+2); /* here is password */
int result;
NETOBJ obj;
char password[80];
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2));
upstr(obj.name);
strmaxcpy(password, (char*)(p1+1),
max(sizeof(password)-1, (int) *p1));
DPRINTF(("LOGIN unencrypted PW NAME='%s', PASSW='%s'\n",
obj.name, password));
if (0 == (result = find_obj_id(&obj, 0))) {
/* TODO: check password !!!!!!! */
;;
}
if (!result) {
c->object_id = obj.id; /* actuell Object ID */
c->t_login = akttime; /* u. login Time */
} else completition = (uint8) -result;
} break;
case 0x16 : { /* Get Connection Info, OLD */
struct XDATA {
uint8 object_id[4];
uint8 object_type[2];
uint8 object_name[48];
uint8 login_time[7];
uint8 reserved;
} *xdata = (struct XDATA*) responsedata;
int conn = (uint16)*(rdata); /* Connection Nr */
memset(xdata, 0, sizeof(struct XDATA));
data_len = sizeof(struct XDATA);
if (conn && conn <= anz_connect
&& connections[conn-1].fd > -1 ) {
CONNECTION *cx=&(connections[conn-1]);
NETOBJ obj;
int result;
obj.id = cx->object_id;
result = nw_get_obj(&obj);
if (!result) {
memset(xdata, 0, sizeof(struct XDATA));
U32_TO_BE32(obj.id, xdata->object_id);
U16_TO_BE16(obj.type, xdata->object_type);
strncpy(xdata->object_name, obj.name, 48);
get_login_time(xdata->login_time, cx);
} /* else completition = (uint8)(-result); */
} else if (!conn || conn > MAX_CONNECTIONS) {
data_len = 0;
completition = 0xfd;
}
} break;
case 0x17 : { /* get crypt key */
int k = sizeof(c->crypt_key);
uint8 *p = c->crypt_key;
uint8 *pp = responsedata;
data_len = k;
while (k--) *pp++ = *p++ = (uint8) rand();
}
break;
case 0x18 : { /* crypt_keyed LOGIN */
uint8 *p = rdata+sizeof(c->crypt_key);
NETOBJ obj;
int result;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), *(p+2));
upstr(obj.name);
DPRINTF(("LOGIN CRYPTED PW NAME='%s'\n",obj.name));
if (0 == (result = find_obj_id(&obj, 0))) {
/* TODO: check password !!!!!!! */
;;
}
if (!result) {
c->object_id = obj.id; /* actuell Object */
c->t_login = akttime; /* and login time */
} else completition = (uint8) -result;
}
break;
case 0x1c : { /* Get Connection Info, new */
struct XDATA {
uint8 object_id[4];
uint8 object_type[2];
uint8 object_name[48];
uint8 login_time[7];
uint8 reserved;
} *xdata = (struct XDATA*) responsedata;
int conn = (uint16)*(rdata); /* Connection Nr */
if (conn && --conn < anz_connect){
CONNECTION *cx=&(connections[conn]);
NETOBJ obj;
int result;
obj.id = cx->object_id;
result = nw_get_obj(&obj);
if (!result) {
memset(xdata, 0, sizeof(struct XDATA));
U32_TO_BE32(obj.id, xdata->object_id);
U16_TO_BE16(obj.type, xdata->object_type);
strncpy(xdata->object_name, obj.name, 48);
get_login_time(xdata->login_time, cx);
data_len = sizeof(struct XDATA);
} else completition = (uint8)(-result);
} else completition = 0xff;
} break;
case 0x32 : { /* Create Bindery Object */
NETOBJ obj;
int result;
uint8 *p = rdata;
obj.flags = *p++;
obj.security = *p++;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)p+3, (int) *(p+2));
result = nw_create_obj(&obj, 0);
if (result < 0) completition = (uint8) -result;
} break;
case 0x33 : { /* delete OBJECT */
uint8 *p = rdata;
int result;
NETOBJ obj;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2));
result = nw_delete_obj(&obj);
if (result < 0) completition = (uint8) -result;
} break;
case 0x34 : { /* rename OBJECT, only SU */
uint8 *p = rdata;
int result;
NETOBJ obj;
uint8 newname[256];
uint8 *p1 = p+3 + *(p+2); /* new Name Length */
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2));
strmaxcpy((char*)newname, (char*)(p1+1), (int) *(p1));
result = nw_rename_obj(&obj, newname);
if (result) completition = (uint8) -result;
} break;
case 0x35 : { /* get Bindery Object ID */
struct XDATA {
uint8 object_id[4];
uint8 object_type[2];
uint8 object_name[48];
} *xdata = (struct XDATA*) responsedata;
uint8 *p = rdata;
int result;
NETOBJ obj;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), (int) *(p+2));
result = find_obj_id(&obj, 0);
if (!result){
U32_TO_BE32(obj.id, xdata->object_id);
U16_TO_BE16(obj.type, xdata->object_type);
strncpy(xdata->object_name, obj.name, 48);
data_len = sizeof(struct XDATA);
} else completition = (uint8) -result;
} break;
case 0x36 : { /* get Bindery Object Name */
struct XDATA {
uint8 object_id[4];
uint8 object_type[2];
uint8 object_name[48];
} *xdata = (struct XDATA*) responsedata;
uint8 *p = rdata;
int result;
NETOBJ obj;
obj.id = GET_BE32(p);
result = nw_get_obj(&obj);
if (!result){
U32_TO_BE32(obj.id, xdata->object_id);
U16_TO_BE16(obj.type, xdata->object_type);
strncpy(xdata->object_name, obj.name, 48);
data_len = sizeof(struct XDATA);
} else completition = (uint8) -result;
} break;
case 0x37 : { /* Scan Bindery Object */
struct XDATA {
uint8 object_id[4];
uint8 object_type[2];
uint8 object_name[48];
uint8 object_flag;
uint8 object_security;
uint8 object_has_properties;
} *xdata = (struct XDATA*) responsedata;
uint32 last_obj_id = GET_BE32(rdata);
uint8 *p = rdata+4;
int result;
NETOBJ obj;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3),(int) *(p+2));
result = find_obj_id(&obj, last_obj_id);
if (!result){
U32_TO_BE32(obj.id, xdata->object_id);
U16_TO_BE16(obj.type, xdata->object_type);
strncpy(xdata->object_name, obj.name, 48);
xdata->object_flag = obj.flags;
xdata->object_security = obj.security;
if (nw_obj_has_prop(&obj) > 0)
xdata->object_has_properties = 0xff;
else xdata->object_has_properties = 0;
data_len = sizeof(struct XDATA);
} else completition = (uint8) -result;
}
break;
case 0x38 : { /* change Bindery Objekt Security */
/* only SU ! */
uint8 *p = rdata;
int result;
NETOBJ obj;
obj.type = GET_BE16(p+1);
strmaxcpy((char*)obj.name, (char*)(p+4), (int) *(p+3));
result = nw_change_obj_security(&obj, (int)*p);
} break;
case 0x39 : { /* create Property */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+=2);
uint8 *object_name = ++p;
int prop_flags = (int) *(p+=object_namlen);
int prop_security = (int) *(++p);
int prop_namlen = (int) *(++p);
uint8 *prop_name = ++p;
int result = nw_create_prop( object_type,
object_name, object_namlen,
prop_name, prop_namlen,
prop_flags, prop_security);
if (result) completition = (uint8) -result;
} break;
case 0x3a : { /* delete property */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+2);
uint8 *object_name= p+3;
int prop_namlen = (int) *(p+3+object_namlen);
uint8 *prop_name = p+4+object_namlen;
int result = nw_delete_property( object_type,
object_name, object_namlen,
prop_name, prop_namlen);
if (result < 0) completition = (uint8) -result;
} break;
case 0x3b : { /* Change Prop Security */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+=2);
uint8 *object_name= ++p;
int prop_security = (int) *(p+=object_namlen);
int prop_namlen = (int) *(++p);
uint8 *prop_name = ++p;
int result = nw_change_prop_security(object_type,
object_name, object_namlen,
prop_name, prop_namlen, prop_security);
if (result) completition = (uint8) -result;
} break;
case 0x3c : { /* Scan Property */
struct XDATA {
uint8 prop_name[16];
uint8 flags; /* set=2, dynamic=1 */
uint8 security;
uint8 akt_scan[4];
uint8 has_value; /* ff, if there are Prop's Values */
uint8 weisnicht;
} *xdata = (struct XDATA*) responsedata;
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+2);
uint8 *object_name = (p+=3);
uint32 last_scan = GET_BE32((p+object_namlen));
uint8 prop_namlen = (int)* (p+=object_namlen+4);
uint8 *prop_name = ++p;
NETPROP prop;
int result = nw_scan_property(&prop,
object_type, object_name, object_namlen,
prop_name, prop_namlen, &last_scan);
if (result > -1) {
strncpy(xdata->prop_name,
prop.name, sizeof(xdata->prop_name));
U32_TO_BE32(last_scan, xdata->akt_scan);
xdata->flags = prop.flags;
xdata->security = prop.security;
xdata->has_value = (uint8) result;
xdata->weisnicht = 0x0;
data_len = sizeof(struct XDATA);
} else completition = (uint8) -result;
} break;
case 0x3d : { /* read Bindery Property Value */
struct XDATA {
uint8 property_value[128];
uint8 more_segments;
uint8 property_flags;
} *xdata = (struct XDATA*) responsedata;
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+2);
uint8 *object_name= p+3;
int segment_nr = (int) *(p+3+object_namlen);
int prop_namlen = (int) *(p+4+object_namlen);
uint8 *prop_name = p+5+object_namlen;
int result = nw_get_prop_val( object_type,
object_name, object_namlen,
segment_nr,
prop_name, prop_namlen,
xdata->property_value,
&(xdata->more_segments),
&(xdata->property_flags));
if (!result){
data_len = sizeof(struct XDATA);
} else completition = (uint8) -result;
} break;
case 0x3e : { /* write Bindery Property Value */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+2);
uint8 *object_name= p+3;
int segment_nr = (int) *(p+3+object_namlen);
int erase_segment = (int) *(p+4+object_namlen);
int prop_namlen = (int) *(p+5+object_namlen);
uint8 *prop_name = p+6+object_namlen;
uint8 *valdata = p+6+object_namlen+prop_namlen;
int result = nw_write_prop_value( object_type,
object_name, object_namlen,
segment_nr, erase_segment,
prop_name, prop_namlen,
valdata);
if (result) completition = (uint8) -result;
} break;
case 0x40: { /* change object password */
;
} break;
case 0x41 : { /* add Bindery Object to Set */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+=2);
uint8 *object_name= ++p;
int prop_namlen = (int) *(p+=object_namlen);
uint8 *prop_name = ++p;
int member_type = GET_BE16(p+prop_namlen);
int member_namlen = (int) *(p+=(prop_namlen+2));
uint8 *member_name= ++p;
int result = nw_add_obj_to_set( object_type,
object_name, object_namlen,
prop_name, prop_namlen,
member_type,
member_name, member_namlen);
if (result) completition = (uint8) -result;
} break;
case 0x42 : { /* delete Bindery Object from Set */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+=2);
uint8 *object_name= ++p;
int prop_namlen = (int) *(p+=object_namlen);
uint8 *prop_name = ++p;
int member_type = GET_BE16(p+prop_namlen);
int member_namlen = (int) *(p+=(prop_namlen+2));
uint8 *member_name= ++p;
int result = nw_delete_obj_from_set( object_type,
object_name, object_namlen,
prop_name, prop_namlen,
member_type,
member_name, member_namlen);
if (result) completition = (uint8) -result;
} break;
case 0x43 : { /* is Bindery Object in Set */
uint8 *p = rdata;
int object_type = GET_BE16(p);
int object_namlen = (int) *(p+=2);
uint8 *object_name= ++p;
int prop_namlen = (int) *(p+=object_namlen);
uint8 *prop_name = ++p;
int member_type = GET_BE16(p+prop_namlen);
int member_namlen = (int) *(p+=(prop_namlen+2));
uint8 *member_name= ++p;
int result = nw_is_obj_in_set( object_type,
object_name, object_namlen,
prop_name, prop_namlen,
member_type,
member_name, member_namlen);
if (result) completition = (uint8) -result;
} break;
case 0x44 : { /* CLOSE BINDERY */
;
} break;
case 0x45 : { /* OPEN BINDERY */
;
} break;
case 0x46 : { /* GET BINDERY ACCES LEVEL */
#if 0
struct XDATA {
uint8 acces_level;
uint8 object_id[4];
} *xdata = (struct XDATA*) responsedata;
#else
uint8 *xdata = responsedata;
#endif
NETOBJ obj;
obj.id = c->object_id;
if (0 != obj.id) {
int result = nw_get_obj(&obj);
if (!result) {
*xdata = obj.security;
U32_TO_BE32(obj.id, (xdata+1));
DPRINTF(("ACCESS LEVEL:=0x%x, obj=0x%lx\n",
(int) obj.security, obj.id));
data_len = 5;
} else completition = (uint8)-result;
} else {
*xdata = 0;
memset(xdata+1, 0xff, 4);
data_len = 5;
}
}
break;
case 0x47 : { /* SCAN BINDERY OBJECT TRUSTEE PATH */
/* TODO !!! */
completition = (uint8)0xff;
}
break;
case 0x48 : { /* GET BINDERY ACCES LEVEL from OBJECT ??? */
struct XDATA {
uint8 acces_level;
} *xdata = (struct XDATA*) responsedata;
NETOBJ obj;
int result;
obj.id = GET_BE32(rdata);
result = nw_get_obj(&obj);
if (!result) {
xdata->acces_level = obj.security;
data_len = sizeof(struct XDATA);
} else completition = (uint8)-result;
}
break;
case 0x49 : { /* IS CALLING STATION A MANAGER */
NETOBJ obj;
int result;
obj.id = GET_BE32(rdata);
/* TODO !! */
completition = 0; /* here allways Manager */
/* not manager, then completition = 0xff */
}
break;
case 0x4a : { /* keyed verify password */
uint8 *p = rdata+sizeof(c->crypt_key);
NETOBJ obj;
int result;
obj.type = GET_BE16(p);
strmaxcpy((char*)obj.name, (char*)(p+3), *(p+2));
upstr(obj.name);
DPRINTF(("TODO:Keyed Verify PW from OBJECT='%s'\n",obj.name));
if (0 == (result = find_obj_id(&obj, 0))) {
/* TODO: check password !!!!!!! */
;;
}
if (!result) {
;;;
} else
completition = (uint8) -result;
}
break;
case 0x4b : { /* keyed change pasword */
uint8 *p = rdata+sizeof(c->crypt_key);
NETOBJ obj;
int result;
uint8 *pw;
int pw_len;
obj.type = GET_BE16(p);
p+=2;
strmaxcpy((char*)obj.name, (char*)(p+1), *p);
upstr(obj.name);
p += (*p+1); /* here is now password */
DPRINTF(("TODO:Keyed Change PW from OBJECT='%s'\n",obj.name));
if (0 == (result = find_obj_id(&obj, 0))) {
/* TODO: check password !!!!!!! */
;;
}
if (!result) {
;;;
/* completition = 0xff; (password not ok) */
} else
completition = 0xff; /* password not ok) */
/* completition = (uint8) -result; */
}
break;
#if 0
case 0x4c : { /* List Relations of an Object */
} break;
#endif
case 0x64 : { /* Create Queue */
/* !!!!!! TO DO */
DPRINTF(("Create QUEUE ??\n"));
} break;
case 0x66 : { /* Read Queue Current Status */
/* !!!!!! TO DO */
NETOBJ obj;
obj.id = GET_BE32(rdata);
DPRINTF(("READ QUEUE STATUS von Q=0x%lx\n", obj.id));
completition=0xd5; /* no Queue Job */
}break;
case 0x6B : { /* Get Queue Job List, old */
/* !!!!!! TO DO */
NETOBJ obj;
obj.id = GET_BE32(rdata);
DPRINTF(("GET QUEUE JOB LIST von Q=0x%lx\n", obj.id));
completition=0xd5; /* no Queue Job */
}break;
case 0x6C : { /* Get Queue Job Entry */
/* !!!!!! TODO */
NETOBJ obj;
obj.id = GET_BE32(rdata);
DPRINTF(("TODO: GET QUEUE JOB ENTRY von Q=0x%lx\n", obj.id));
completition=0xd5; /* no Queue Job */
}break;
case 0x79: { /* creat queue job and file */
uint32 q_id = GET_BE32(rdata);
uint8 *dir_name = rdata+4+280+1;
int result = nw_get_q_dirname(q_id, dir_name);
if (result > -1) {
*(dir_name-1) = result;
in_len = 295 + result;
return(-1); /* nwconn must do the rest !!!!! */
} else completition = (uint8) -result;
}
break;
case 0x7f: { /* close file and start queue */
uint32 q_id = GET_BE32(rdata);
uint8 *prc = rdata+4+4+1;
int result = nw_get_q_prcommand(q_id, prc);
if (result > -1) {
*(prc-1) = result;
in_len = 19 + result;
return(-1); /* nwconn must do the rest !!!!! */
} else completition = (uint8) -result;
}
break;
case 0xc8 : { /* CHECK CONSOLE PRIVILEGES */
DPRINTF(("TODO: CHECK CONSOLE PRIV \n"));
/* !!!!!! TODO completition=0xc6 (no rights) */
} break;
case 0xc9 : { /* GET FILE SERVER DESCRIPTION STRINGs */
char *company = "Mars";
char *revision = "Version %d.%d";
char *revision_date= "22-Nov-95";
char *copyright = "(C)opyright Martin Stover";
int k=strlen(company)+1;
memset(responsedata, 0, 512);
strcpy(responsedata, company);
k += (1+sprintf(responsedata+k, revision,
_VERSION_H_, _VERSION_L_ ));
strcpy(responsedata+k, revision_date);
k += (strlen(revision_date)+1);
strcpy(responsedata+k, copyright);
k += (strlen(copyright)+1);
data_len = k;
} break;
case 0xcd : { /* GET FILE SERVER LOGIN STATUS */
struct XDATA {
uint8 login_allowed; /* 0 NO , 1 YES */
} *xdata = (struct XDATA*) responsedata;
xdata->login_allowed = 1;
data_len = 1;
}
break;
case 0xd1 : /* Send Console Broadcast (old) */
{
uint8 *p = rdata;
int anz_conns = (int) *p++;
uint8 *co = p;
int msglen = (int) *(p+anz_conns);
char *msg = p+anz_conns+1;
int k = -1;
if (anz_conns) {
while (++k < anz_conns) {
int conn= (int) *co++;
if (conn == ncprequest->connection) {
strmaxcpy(c->message, msg, min(58, msglen));
connect_status = 0x40; /* don't know why */
} else if (conn && --conn < anz_connect) {
CONNECTION *cc= &(connections[conn]);
if (cc->object_id) { /* if logged */
strmaxcpy(cc->message, msg, min(58, msglen));
write_to_nwserv(0x8888, conn+1, NULL, 0);
}
}
}
} else {
strmaxcpy(c->message, msg, min(58, msglen));
connect_status = 0x40; /* don't know why */
}
}
break;
#if 0
case 0xfd : /* Send Console Broadcast (new) */
return(-1); /* nicht erkannt */
break;
case 0xd3 : { /* down File Server */
}
break;
#endif
default : return(-1); /* not known here */
} /* switch */
} else return(-1); /* not kwown here */
U16_TO_BE16(0x3333, ncpresponse->type);
ncpresponse->sequence = ncprequest->sequence;
ncpresponse->connection = ncprequest->connection;
ncpresponse->reserved = 0;
ncpresponse->completition = completition;
ncpresponse->connect_status = connect_status;
data_len=write(c->fd, (char*)ncpresponse,
sizeof(NCPRESPONSE) + data_len);
DPRINTF(("0x%x 0x%x compl:0x%x, write to %d, anz = %d\n",
func, (int)ufunc, (int) completition, c->fd, data_len));
return(0); /* ok */
}
static void ncp_response(int type, int sequence,
int connection, int task,
int completition, int connect_status,
int data_len)
{
IPX_DATA ipx_out_data;
NCPRESPONSE *ncpresponse=(NCPRESPONSE*)&ipx_out_data;
U16_TO_BE16(type, ncpresponse->type);
ncpresponse->sequence = (uint8) sequence;
ncpresponse->connection = (uint8) connection;
ncpresponse->task = (uint8) task;
ncpresponse->reserved = 0;
ncpresponse->completition = (uint8)completition;
ncpresponse->connect_status = (uint8)connect_status;
if (nw_debug){
char comment[80];
sprintf(comment, "NCP-RESP compl=0x%x ", completition);
send_ipx_data(ncp_fd, 17, sizeof(NCPRESPONSE) + data_len,
(char *) ncpresponse,
&from_addr, comment);
} else
send_ipx_data(ncp_fd, 17, sizeof(NCPRESPONSE) + data_len,
(char *) ncpresponse,
&from_addr, NULL);
}
static void sig_child(int isig)
{
int k=-1;
int status;
int pid=wait(&status);
while (++k < anz_connect) {
CONNECTION *c = &connections[k];
if (c->pid == pid) {
clear_connection(k+1);
break;
}
}
signal(SIGCHLD, sig_child);
}
static int fl_got_hup=0;
static void sig_hup(int rsig)
{
signal(SIGHUP, SIG_IGN);
fl_got_hup++;
signal(SIGHUP, sig_hup);
}
void set_sig(void)
{
signal(SIGCHLD, sig_child);
signal(SIGHUP, sig_hup);
}
static void handle_bind_calls(uint8 *p)
{
int func = (int) *p;
p += 2;
switch (func) {
case 0x01 :
{ /* insert NET_ADDRESS */
NETOBJ obj;
obj.type = GET_BE16(p);
p += 2;
strmaxcpy(obj.name, p+1, *p);
p += (*p+1);
nw_new_create_prop(0, obj.name, obj.type, O_FL_DYNA, 0x40,
"NET_ADDRESS", P_FL_DYNA|P_FL_ITEM, 0x40,
(char *)p, sizeof(ipxAddr_t));
}
break;
case 0x02 :
{ /* delete complete Object */
NETOBJ obj;
obj.type = GET_BE16(p);
p += 2;
strmaxcpy(obj.name, p+1, *p);
nw_delete_obj(&obj); /* also deletes all properties */
}
break;
default : break;
}
}
static int handle_ctrl(void)
{
int what;
int conn;
int result = 0;
int data_len = read(0, (char*)&what, sizeof(what));
if (data_len == sizeof(what)) {
DPRINTF(("NCPSERV:GOT CTRL what=0x%x\n", what));
switch (what) {
case 0x5555 : /* clear_connection */
data_len = read(0, (char*)&conn, sizeof(conn));
if (sizeof(int) == data_len) clear_connection(conn);
break;
case 0x3333 : /* 'bindery' calls */
if (sizeof(conn) == read(0, (char*)&conn, sizeof(conn))) {
uint8 *buff = xmalloc(conn+10);
XDPRINTF((2, "0x3333 len=%d\n", conn));
if (conn == read(0, (char*)buff, conn))
handle_bind_calls(buff);
else
DPRINTF(("0x3333 protokoll error:len=%d\n", conn));
xfree(buff);
}
break;
case 0xeeee:
get_ini_debug(2);
break;
default : break;
} /* switch */
result++;
} else DPRINTF(("NCPSERV:GOT CTRL size=%d\n", data_len));
return(result);
}
static void handle_hup(void)
{
signal(SIGHUP, SIG_IGN);
XDPRINTF((2, "HANDLE_HUP_BEGIN\n"));
fl_got_hup = handle_ctrl();
XDPRINTF((2, "HANDLE_HUP_END fl_got_hup=%d\n", fl_got_hup));
signal(SIGHUP, sig_hup);
}
int main(int argc, char *argv[])
{
int result;
int type;
if (argc != 8) {
fprintf(stderr, "usage ncpserv address nwname GID UID debug1 debug2 debug3\n");
exit(1);
}
strncpy(my_nwname, argv[1], 48);
my_nwname[47] = '\0';
adr_to_ipx_addr(&my_addr, argv[2]);
nw_init_dbm(my_nwname, &my_addr);
sscanf(argv[3], "%d", &conn_gid);
sscanf(argv[4], "%d", &conn_uid);
sscanf(argv[5], "%d", &nw_debug);
sscanf(argv[6], "%d", &nwconn_debug);
sscanf(argv[7], "%d", &ipxdebug);
#ifdef LINUX
set_emu_tli(ipxdebug);
#endif
if (open_ncp_socket()) exit(1);
ud.opt.len = sizeof(ipx_pack_typ);
ud.opt.maxlen = sizeof(ipx_pack_typ);
ud.opt.buf = (char*)&ipx_pack_typ; /* gets actual Typ */
ud.addr.len = sizeof(ipxAddr_t);
ud.addr.maxlen = sizeof(ipxAddr_t);
ud.addr.buf = (char*)&from_addr;
ud.udata.len = IPX_MAX_DATA;
ud.udata.maxlen = IPX_MAX_DATA;
ud.udata.buf = (char*)&ipx_in_data;
set_sig();
fcntl(0, F_SETFL, O_NONBLOCK); /* non blocking input pipe */
while (1) {
time(&akttime);
if ((result = t_rcvudata(ncp_fd, &ud, &rcv_flags)) > -1){
in_len = ud.udata.len;
if (fl_got_hup) handle_hup();
XDPRINTF((10, "NCPSERV-LOOP von %s\n", visable_ipx_adr(&from_addr)));
if ((type = GET_BE16(ncprequest->type)) == 0x2222 || type == 0x5555) {
int connection = (int)ncprequest->connection;
XDPRINTF((10, "GOT 0x%x in NCPSERV connection=%d\n", type, connection));
if ( connection > 0 && connection <= anz_connect) {
CONNECTION *c = &(connections[connection-1]);
if (!memcmp(&from_addr, &(c->client_adr), sizeof(ipxAddr_t))) {
if (c->fd > -1){
if (type == 0x2222) {
int sent_here = 1;
int func = ncprequest->function;
int diff_time = akttime - c->last_access;
c->last_access = akttime;
if (diff_time > 50) /* after max. 50 seconds */
write_to_nwserv(0x4444, connection, NULL,0);
/* tell the wdog there's no need to look */
if (ncprequest->sequence == c->sequence
&& !c->retry++) {
/* perhaps nwconn is busy */
ncp_response(0x9999, ncprequest->sequence,
connection, 0, 0x0, 0, 0);
DPRINTF(("Send Request being serviced to connection:%d\n", connection));
continue;
}
switch (func) {
case 0x15 : /* Messages */
case 0x17 : /* File Server Environment */
sent_here = handle_fxx(c, in_len, func);
break;
default : break;
} /* switch */
if (sent_here) {
int anz=write(c->fd, (char*)ncprequest, in_len);
XDPRINTF((10, "write to %d, anz = %d\n", c->fd, anz));
if (func == 0x19) { /* logout */
c->object_id = 0; /* not LOGGED */
}
}
c->sequence = ncprequest->sequence; /* save last sequence */
c->retry = 0;
continue;
} else { /* 0x5555 */
if ( (uint8) (c->sequence+1) == (uint8) ncprequest->sequence) {
clear_connection(ncprequest->connection);
ncp_response(0x3333,
ncprequest->sequence,
connection,
1, 0x0, 0, 0);
continue;
}
}
}
XDPRINTF((10, "c->fd = %d\n", c->fd));
}
}
/* here someting is wrong */
XDPRINTF((0, "GOT 0x%x connection=%d of %d conns not OK in NCPSERV\n",
type, ncprequest->connection, anz_connect));
ncp_response(0x3333, ncprequest->sequence,
ncprequest->connection,
0, 0xf9, 0, 0);
} else if (type == 0x1111) {
/* GIVE CONNECTION Nr connection */
int connection = find_get_conn_nr(&from_addr);
DPRINTF(("GIVE CONNECTION NR=%d in NCPSERV\n", connection));
if (connection) {
CONNECTION *c = &(connections[connection-1]);
int anz;
c->message[0] = '\0';
c->object_id = 0; /* firsttime set 0 for NOT LOGGED */
c->sequence = 0;
anz=write(c->fd, (char*)ncprequest, in_len);
XDPRINTF((10, "write to oldconn %d, anz = %d\n", c->fd, anz));
} else /* no free connection */
ncp_response(0x3333, 0, 0, 0, 0xf9, 0, 0);
} else {
int connection = (int)ncprequest->connection;
int sequence = (int)ncprequest->sequence;
XDPRINTF((0, "UNKNOWN TYPE: 0x%x\n", type));
ncp_response(0x3333, sequence, connection,
1, 0xfb, 0, 0);
}
} else {
if (fl_got_hup) handle_hup();
else t_error("NCPSERV t_rcvudata");
}
}
printf("LEAVE ncpserv\n");
t_unbind(ncp_fd);
t_close(ncp_fd);
return(0);
}