1 /**********************************************************
2  * File: qipc_common.c
3  * Created at Mon May 7 23:07:41 2001  by lev // lev@serebryakov.spb.ru
4  *
5  * $Id: qipc_common.c,v 1.6 2001/09/17 18:56:48 lev Exp $
6  **********************************************************/
7 #include "headers.h"
8 #include <stdarg.h>
9 #include "byteop.h"
10 
11 /* Allocate and receive IPC packet via UDP -- should be freed with xfree() */
receive_ipc_packet_udp(int s,struct sockaddr_in * sa)12 evtany_t *receive_ipc_packet_udp(int s, struct sockaddr_in *sa)
13 {
14 	BYTE bf[4];
15 	UINT32 l;
16     evtany_t *pkt;
17 
18 	if(recvfrom(s,bf,4,MSG_PEEK,sa,sizeof(*sa))!=4) return NULL;
19 	l = FETCH32(bf);
20 	if(!(pkt = xmalloc(l))) return NULL;
21 	if(recvfrom(s,pkt,l,MSG_WAITALL,sa,sizeof(*sa))!=l) {
22 		xfree(pkt);
23 		return NULL;
24 	}
25 	pkt->fulllength = l;
26 	return pkt;
27 }
28 
29 /* Allocate and receive IPC packet via TCP -- should be freed with xfree() */
receive_ipc_packet_tcp(int s)30 evtany_t *receive_ipc_packet_tcp(int s)
31 {
32 	BYTE bf[4];
33 	UINT32 l;
34     evtany_t *pkt;
35 
36 	if(recv(s,bf,4,MSG_PEEK)!=4) return NULL;
37 	l = FETCH32(bf);
38 	if(!(pkt = xmalloc(l))) return NULL;
39 	if(recv(s,pkt,l,MSG_WAITALL)!=l) {
40 		xfree(pkt);
41 		return NULL;
42 	}
43 	pkt->fulllength = l;
44 	return pkt;
45 }
46 
47 /* Decode packet by signature */
unpack_ipc_packet(CHAR * data,int * len,char * sig,...)48 int unpack_ipc_packet(CHAR *data, int *len, char *sig, ...)
49 {
50 	va_list args;
51 	DWORD *pl;
52 	CHAR *pc;
53 	CHAR *ps;
54 	CHAR **pps;
55 	ftnaddr_t *pa;
56 	ninfo_t *pn;
57 	slist_t **ppsl, *psl;
58     faslist_t **ppasl, *pasl;
59 	falist_t **ppal, *pal;
60 	long l,i,N;
61 	int rc = 0;
62 
63 	va_start(args, sig);
64 
65 	while(*sig) {
66 		switch(*sig) {
67 		case 's':		/* Strings, allocate here */
68 			if(*len<4) { va_end(args); return rc; }
69 			l=FETCH32(data); INC32(data); *len-=4;
70 			pps=va_arg(args,CHAR **);
71 			if(l) {
72 				if(*len<l || data[l-1]) { va_end(args); return rc; }
73 				*pps=xmalloc(l);
74 				memcpy(*pps,data,l); *len-=l; data+=l;
75 			} else {
76 				*pps=NULL;
77 			}
78 			rc++;
79 			break;
80 		case 'd':		/* 32 bit unsigned integer */
81 			if(*len<4) { va_end(args); return rc; }
82 			pl=va_arg(args, DWORD *);
83 			*pl=FETCH32(data); INC32(data); *len-=4;
84 			rc++;
85 			break;
86 		case 'c':		/* One character */
87 			if(!*len) { va_end(args); return rc; }
88 			pc=va_arg(args,CHAR *);
89 			*pc=*data; data++; *len--;
90 			rc++;
91 			break;
92 		case 'a':		/* 4D FTN address */
93 			if(*len<2*4) { va_end(args); return rc; }
94 			pa=va_arg(args,ftnaddr_t *);
95 			pa->z=FETCH16(data); INC16(data); *len-=2;
96 			pa->n=FETCH16(data); INC16(data); *len-=2;
97 			pa->f=FETCH16(data); INC16(data); *len-=2;
98 			pa->p=FETCH16(data); INC16(data); *len-=2;
99 			rc++;
100 			break;
101 		case 'l':		/* List of strings or addresses */
102 			if(*len<2) { va_end(args); return rc; }
103 			N=FETCH16(data); INC16(data); *len-=2;
104 			sig++;
105 			switch(*sig) {
106 			case 's':	/* List of strings (slist_t) */
107 				if(*len<4*N) { va_end(args); return rc; }
108 				ppsl=va_arg(args,slist_t **);
109 				psl=*ppsl=NULL;
110 				for(i=0;i<N;i++) {
111 					if(!psl) psl=*ppsl=xcalloc(1,sizeof(*psl));
112 					else { psl->next=xcalloc(1,sizeof(*psl)); psl=psl->next; }
113 					l=*len;
114 					if(1!=unpack_ipc_packet(data,len,"s",&psl->str)) { va_end(args); return rc; }
115 					data+=(l-*len);
116 				}
117 				break;
118 			case 'a':	/* List of addresses (falist_t) */
119 				if(*len<8*N) { va_end(args); return rc; }
120 				ppal=va_arg(args,falist_t **);
121 				pal=*ppal=NULL;
122 				for(i=0;i<N;i++) {
123 					if(!pal) pal=*ppal=xcalloc(1,sizeof(*pal));
124 					else { pal->next=xcalloc(1,sizeof(*pal)); pal=pal->next; }
125 					if(1!=unpack_ipc_packet(data,len,"a",&pal->addr)) { va_end(args); return rc; }
126 					data+=8;
127 				}
128 				break;
129 			default:
130 				va_end(args);
131 				return rc;
132 			}
133 			rc++;
134 			break;
135 		case 'n':	/* Node info "lassssdsds" */
136 			pn=va_arg(args,ninfo_t *);
137 			l=*len;
138 			if(9!=unpack_ipc_packet(data,len,"lassssdsds",
139 					&pn->addrs,
140 					&pn->name,
141 					&pn->place,
142 					&pn->sysop,
143 					&pn->phone,
144 					&pn->speed,
145 					&pn->flags,
146 					&pn->time,
147 					&pn->wtime)) { va_end(args); return rc; }
148 			data+=(l-*len);
149 			break;
150 		default:
151 			va_end(args);
152 			return rc;
153 		}
154 		sig++;
155 	}
156 	va_end(args);
157 	return rc;
158 }
159 
160 /* Encode packet by signature */
pack_ipc_packet(CHAR * data,int maxlen,int * len,char * sig,...)161 int pack_ipc_packet(CHAR *data, int maxlen, int *len, char *sig, ...)
162 {
163 	va_list args;
164 	DWORD pl;
165 	CHAR pc;
166 	CHAR *ps;
167 	ftnaddr_t *pa;
168 	long l;
169 	int slen = maxlen;
170 	int rc = 0;
171 
172 	*len=0;
173 	va_start(args, sig);
174 	while(*sig) {
175 		switch(*sig) {
176 		case 's':		/* String */
177 			if(maxlen<4) { va_end(args); return rc; }
178 			ps=va_arg(args,CHAR *);
179 			if(ps) l=strlen(ps)+1;
180 			else l=0;
181 			STORE32(data,l); INC32(data); maxlen-=4;
182 			if(l) {
183 				if(maxlen<l) { va_end(args); return rc; }
184 				memcpy(data,ps,l); data+=l; maxlen-=l;
185 			}
186 			rc++;
187 			break;
188 		case 'd':		/* 32bit unsigned integer */
189 			if(maxlen<4) { va_end(args); return rc; }
190 			pl=va_arg(args, DWORD);
191 			STORE32(data,pl); INC32(data); maxlen-=4;
192 			rc++;
193 			break;
194 		case 'c':		/* One character */
195 			if(!maxlen) { va_end(args); return rc; }
196 			pc=va_arg(args,CHAR);
197 			*data=pc; data++; maxlen--;
198 			rc++;
199 			break;
200 		case 'a':		/* 4D FTN address */
201 			if(maxlen<8) { va_end(args); return rc; }
202 			pa=va_arg(args,ftnaddr_t);
203 			STORE16(data,pa->z); INC32(data); maxlen-=2;
204 			STORE16(data,pa->n); INC32(data); maxlen-=2;
205 			STORE16(data,pa->f); INC32(data); maxlen-=2;
206 			STORE16(data,pa->p); INC32(data); maxlen-=2;
207 			rc++;
208 			break;
209 		case 'l':		/* List of strings or addresses */
210 			if(maxlen<2) { va_end(args); return rc; }
211 			*ps=data;
212 			N=0;
213 			STORE16(data,N); INC16(data); *len-=2;
214 			sig++;
215 			switch(*sig) {
216 			case 's':	/* List of strings (slist_t) */
217 				if(maxlen<4*N) { va_end(args); return rc; }
218 				psl=va_arg(args,slist_t *);
219 				if(psl) do {
220 					N++;
221 					if(1!=pack_ipc_packet(data,len,&l,"s",psl->str)) { va_end(args); return rc; }
222 					data+=l;
223 				} while(psl=psl->next);
224 				break;
225 			case 'a':	/* List of addresses (falist_t) */
226 				if(maxlen<4*N) { va_end(args); return rc; }
227 				pal=va_arg(args,falist_t *);
228 				if(pal) do {
229 					N++;
230 					if(1!=pack_ipc_packet(data,len,&l,"a",&pal->addr)) { va_end(args); return rc; }
231 					data+=l;
232 				} while(pal=pal->next);
233 				break;
234 			default:
235 				va_end(args);
236 				return rc;
237 			}
238 			STORE16(ps,(N&0x0000ffff));	/* Store real number of elements back */
239 			rc++;
240 			break;
241 		case 'n':		/* Node info */
242 			pn=va_arg(args,ninfo_t *);
243 			if(9!=pack_ipc_packet(data,len,&l,"lassssdsds",
244 					pn->addrs,
245 					pn->name,
246 					pn->place,
247 					pn->sysop,
248 					pn->phone,
249 					pn->speed,
250 					pn->flags,
251 					pn->time,
252 					pn->wtime)) { va_end(args); return rc; }
253 			data+=l;
254 			break;
255 		default:
256 			va_end(args);
257 			return rc;
258 		}
259 		sig++;
260 	}
261 	va_end(args);
262 	*len=slen-maxlen;
263 	return rc;
264 }
265 
266 /* Encode packet with DES (pkt should be bigger than length!) */
encode_ipc_packet(evtany_t * pkt,sessenccontext_t * cx)267 void encode_ipc_packet(evtany_t *pkt, sessenccontext_t *cx)
268 {
269 	int len8 = ((pkg->fulllength>>3)|(pkg->fulllength&0x07?1:0))<<3;
270 	int i;
271 	for(i=pkg->fulllength;i<len8;i++) pkt->data[i] = 0;
272 	pkg->fulllength = len8;
273 	des_cbc_encrypt(cx->cx,cx->iv,pkg->data,pkg->data,len8);
274 }
275 
276 /* Decode packet with DES (pkt should be bigger than length!) */
decode_ipc_packet(evtany_t * pkt,sessenccontext_t * cx)277 void decode_ipc_packet(evtany_t *pkt, sessenccontext_t *cx)
278 {
279 	int len8 = ((pkg->fulllength>>3)|(pkg->fulllength&0x07?1:0))<<3;
280 	int i;
281 	for(i=pkg->fulllength;i<len8;i++) pkt->data[i] = 0;
282 	pkg->fulllength = len8;
283 	des_cbc_decrypt(cx->cx,cx->iv,pkg->data,pkg->data,len8);
284 }
285