Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / scmio.c
blob47cc40d4bead20205d8e37026b67add409475026
1 /* $NetBSD: scmio.c,v 1.18 2009/10/17 22:26:13 christos Exp $ */
3 /*
4 * Copyright (c) 1992 Carnegie Mellon University
5 * All Rights Reserved.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
28 * SUP Communication Module for 4.3 BSD
30 * SUP COMMUNICATION MODULE SPECIFICATIONS:
32 * IN THIS MODULE:
34 * OUTPUT TO NETWORK
36 * MESSAGE START/END
37 * writemsg (msg) start message
38 * int msg; message type
39 * writemend () end message and flush data to network
41 * MESSAGE DATA
42 * writeint (i) write int
43 * int i; integer to write
44 * writestring (p) write string
45 * char *p; string pointer
46 * writefile (f) write open file
47 * int f; open file descriptor
49 * COMPLETE MESSAGE (start, one data block, end)
50 * writemnull (msg) write message with no data
51 * int msg; message type
52 * writemint (msg,i) write int message
53 * int msg; message type
54 * int i; integer to write
55 * writemstr (msg,p) write string message
56 * int msg; message type
57 * char *p; string pointer
59 * INPUT FROM NETWORK
60 * MESSAGE START/END
61 * readflush () flush any unread data (close)
62 * readmsg (msg) read specified message type
63 * int msg; message type
64 * readmend () read message end
66 * MESSAGE DATA
67 * readskip () skip over one input data block
68 * readint (i) read int
69 * int *i; pointer to integer
70 * readstring (p) read string
71 * char **p; pointer to string pointer
72 * readfile (f) read into open file
73 * int f; open file descriptor
75 * COMPLETE MESSAGE (start, one data block, end)
76 * readmnull (msg) read message with no data
77 * int msg; message type
78 * readmint (msg,i) read int message
79 * int msg; message type
80 * int *i; pointer to integer
81 * readmstr (msg,p) read string message
82 * int msg; message type
83 * char **p; pointer to string pointer
85 * RETURN CODES
86 * All routines normally return SCMOK. SCMERR may be returned
87 * by any routine on abnormal (usually fatal) errors. An
88 * unexpected MSGGOAWAY will result in SCMEOF being returned.
90 * COMMUNICATION PROTOCOL
91 * Messages always alternate, with the first message after
92 * connecting being sent by the client process.
94 * At the end of the conversation, the client process will
95 * send a message to the server telling it to go away. Then,
96 * both processes will close the network connection.
98 * Any time a process receives a message it does not expect,
99 * the "readmsg" routine will send a MSGGOAWAY message and
100 * return SCMEOF.
102 * Each message has this format:
103 * ---------- ------------ ------------ ----------
104 * |msg type| |count|data| |count|data| ... |ENDCOUNT|
105 * ---------- ------------ ------------ ----------
106 * size: int int var. int var. int
108 * All ints are assumed to be 32-bit quantities. A message
109 * with no data simply has a message type followed by ENDCOUNT.
111 **********************************************************************
112 * HISTORY
113 * Revision 1.7 92/09/09 22:04:41 mrt
114 * Removed the data encryption routines from here to netcrypt.c
115 * [92/09/09 mrt]
117 * Revision 1.6 92/08/11 12:05:57 mrt
118 * Brad's changes: Delinted,Added forward declarations of
119 * static functions. Added copyright.
120 * [92/07/24 mrt]
122 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
123 * Added crosspatch support.
125 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
126 * Found error in debugging code for readint().
128 * 01-Apr-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
129 * Added code to readdata to "push" data back into the data buffer.
130 * Added prereadcount() to return the message count size after
131 * reading it and then pushing it back into the buffer. Clear
132 * any encryption when a GOAWAY message is detected before reading
133 * the reason string. [V5.19]
135 * 02-Oct-86 Rudy Nedved (ern) at Carnegie-Mellon University
136 * Put a timeout on reading from the network.
138 * 25-May-86 Jonathan J. Chew (jjc) at Carnegie-Mellon University
139 * Renamed "howmany" parameter to routines "encode" and "decode" from
140 * to "count" to avoid conflict with 4.3BSD macro.
142 * 15-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
143 * Added readflush() to flush any unread data from the input
144 * buffer. Called by requestend() in scm.c module.
146 * 19-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
147 * Added register variables to decode() for speedup. Added I/O
148 * buffering to reduce the number or read/write system calls.
149 * Removed readmfil/writemfil routines which were not used and were
150 * not compatible with the other similarly defined routines anyway.
152 * 19-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
153 * Created from scm.c I/O and crypt routines.
155 **********************************************************************
158 #include "libc.h"
159 #include <errno.h>
160 #include <stdbool.h>
161 #include <sys/types.h>
162 #include <sys/stat.h>
163 #include <sys/file.h>
164 #include <sys/time.h>
165 #include <sys/poll.h>
166 #include "supcdefs.h"
167 #include "supextern.h"
168 #include "supmsg.h"
169 #ifndef INFTIM
170 #define INFTIM -1
171 #endif
173 /*************************
174 *** M A C R O S ***
175 *************************/
177 /* end of message */
178 #define ENDCOUNT (-1) /* end of message marker */
179 #define NULLCOUNT (-2) /* used for sending NULL pointer */
181 #define RETRIES 15 /* # of times to retry io */
182 #define FILEXFER 2048 /* block transfer size */
183 #define XFERSIZE(count) ((count > FILEXFER) ? FILEXFER : count)
185 /*********************************************
186 *** G L O B A L V A R I A B L E S ***
187 *********************************************/
189 extern int netfile; /* network file descriptor */
191 int scmdebug; /* scm debug flag */
193 int cryptflag; /* whether to encrypt/decrypt data */
194 char *cryptbuf; /* buffer for data encryption/decryption */
196 extern char *goawayreason; /* reason for goaway message */
198 struct buf {
199 char b_data[FILEXFER]; /* buffered data */
200 char *b_ptr; /* pointer to end of buffer */
201 int b_cnt; /* number of bytes in buffer */
202 } buffers[2];
203 struct buf *gblbufptr; /* buffer pointer */
205 static int writedata(size_t, void *);
206 static int writeblock(size_t, void *);
207 static int readdata(size_t, void *, bool);
208 static int readcount(int *);
211 /***********************************************
212 *** O U T P U T T O N E T W O R K ***
213 ***********************************************/
215 static int
216 writedata(size_t count, void *data)
217 { /* write raw data to network */
218 int x, tries;
219 struct buf *bp;
221 if (gblbufptr) {
222 if (gblbufptr->b_cnt + count <= FILEXFER) {
223 memcpy(gblbufptr->b_ptr, data, count);
224 gblbufptr->b_cnt += count;
225 gblbufptr->b_ptr += count;
226 return (SCMOK);
228 bp = (gblbufptr == buffers) ? &buffers[1] : buffers;
229 memcpy(bp->b_data, data, count);
230 bp->b_cnt = count;
231 bp->b_ptr = bp->b_data + count;
232 data = gblbufptr->b_data;
233 count = gblbufptr->b_cnt;
234 gblbufptr->b_cnt = 0;
235 gblbufptr->b_ptr = gblbufptr->b_data;
236 gblbufptr = bp;
238 tries = 0;
239 for (;;) {
240 errno = 0;
241 x = write(netfile, data, count);
242 if (x > 0)
243 break;
244 if (errno)
245 break;
246 if (++tries > RETRIES)
247 break;
248 if (scmdebug > 0)
249 logerr("SCM Retrying failed network write");
251 if (x <= 0) {
252 if (errno == EPIPE)
253 return (scmerr(-1, "Network write timed out"));
254 if (errno)
255 return (scmerr(errno, "Write error on network"));
256 return (scmerr(-1, "Write retries failed"));
258 if (x != count)
259 return (scmerr(-1, "Write error on network returned %d "
260 "on write of %zu", x, count));
261 return (SCMOK);
264 static int
265 writeblock(size_t count, void *data)
266 { /* write data block */
267 int x;
268 int y = byteswap((int)count);
270 x = writedata(sizeof(int), &y);
271 if (x == SCMOK)
272 x = writedata(count, data);
273 return (x);
277 writemsg(int msg)
278 { /* write start of message */
279 int x;
281 if (scmdebug > 1)
282 loginfo("SCM Writing message %d", msg);
283 if (gblbufptr)
284 return (scmerr(-1, "Buffering already enabled"));
285 gblbufptr = buffers;
286 gblbufptr->b_ptr = gblbufptr->b_data;
287 gblbufptr->b_cnt = 0;
288 x = byteswap(msg);
289 return (writedata(sizeof(int), &x));
293 writemend(void)
294 { /* write end of message */
295 size_t count;
296 char *data;
297 int x;
299 x = byteswap(ENDCOUNT);
300 x = writedata(sizeof(int), &x);
301 if (x != SCMOK)
302 return (x);
303 if (gblbufptr == NULL)
304 return (scmerr(-1, "Buffering already disabled"));
305 if (gblbufptr->b_cnt == 0) {
306 gblbufptr = NULL;
307 return (SCMOK);
309 data = gblbufptr->b_data;
310 count = gblbufptr->b_cnt;
311 gblbufptr = NULL;
312 return (writedata(count, data));
316 writeint(int i)
317 { /* write int as data block */
318 int x;
319 if (scmdebug > 2)
320 loginfo("SCM Writing integer %d", i);
321 x = byteswap(i);
322 return (writeblock(sizeof(int), &x));
326 writestring(char *p)
327 { /* write string as data block */
328 int len;
329 int x;
330 if (p == NULL) {
331 int y = byteswap(NULLCOUNT);
332 if (scmdebug > 2)
333 loginfo("SCM Writing string NULL");
334 return (writedata(sizeof(int), &y));
336 if (scmdebug > 2)
337 loginfo("SCM Writing string %s", p);
338 len = strlen(p);
339 if (cryptflag) {
340 x = getcryptbuf(len + 1);
341 if (x != SCMOK)
342 return (x);
343 encode(p, cryptbuf, len);
344 p = cryptbuf;
346 return (writeblock((size_t)len, p));
350 writefile(int f)
351 { /* write open file as a data block */
352 char buf[FILEXFER];
353 int number = 0, sum = 0, filesize, x;
354 int y;
355 struct stat statbuf;
357 if (fstat(f, &statbuf) < 0)
358 return (scmerr(errno, "Can't access open file for message"));
359 filesize = (int)statbuf.st_size;
360 y = byteswap(filesize);
361 x = writedata(sizeof(int), &y);
363 if (cryptflag)
364 x = getcryptbuf(FILEXFER);
366 if (x == SCMOK) {
367 sum = 0;
368 do {
369 number = read(f, buf, FILEXFER);
370 if (number > 0) {
371 if (cryptflag) {
372 encode(buf, cryptbuf, number);
373 x = writedata((size_t)number, cryptbuf);
374 } else {
375 x = writedata((size_t)number, buf);
377 sum += number;
379 } while (x == SCMOK && number > 0);
381 if (sum != filesize)
382 return (scmerr(-1, "File size error on output message"));
383 if (number < 0)
384 return (scmerr(errno, "Read error on file output message"));
385 return (x);
389 writemnull(int msg)
390 { /* write message with no data */
391 int x;
392 x = writemsg(msg);
393 if (x == SCMOK)
394 x = writemend();
395 return (x);
399 writemint(int msg, int i)
400 { /* write message of one int */
401 int x;
402 x = writemsg(msg);
403 if (x == SCMOK)
404 x = writeint(i);
405 if (x == SCMOK)
406 x = writemend();
407 return (x);
411 writemstr(int msg, char *p)
412 { /* write message of one string */
413 int x;
414 x = writemsg(msg);
415 if (x == SCMOK)
416 x = writestring(p);
417 if (x == SCMOK)
418 x = writemend();
419 return (x);
421 /*************************************************
422 *** I N P U T F R O M N E T W O R K ***
423 *************************************************/
425 static int
426 readdata(size_t count, void *vdata, bool push)
427 { /* read raw data from network */
428 char *p;
429 int c, n, m, x;
430 static int bufcnt = 0;
431 static char *bufptr;
432 static char buffer[FILEXFER];
433 struct pollfd set[1];
434 char *data = vdata;
436 if (push) {
437 if (bufptr + count < buffer)
438 return (scmerr(-1, "No space in buffer %zu", count));
439 bufptr -= count;
440 bufcnt += count;
441 memcpy(bufptr, data, -count);
442 return (SCMOK);
444 if (count == 0 && data == NULL) {
445 bufcnt = 0;
446 return (SCMOK);
448 if (count <= bufcnt) {
449 memcpy(data, bufptr, count);
450 bufptr += count;
451 bufcnt -= count;
452 return (SCMOK);
454 if (bufcnt > 0) {
455 memcpy(data, bufptr, (size_t)bufcnt);
456 data += bufcnt;
457 count -= bufcnt;
459 bufptr = buffer;
460 bufcnt = 0;
461 set[0].fd = netfile;
462 set[0].events = POLLIN;
463 p = buffer;
464 n = FILEXFER;
465 m = count;
466 while (m > 0) {
467 while ((c = poll(set, 1, 2 * 60 * 60 * 1000)) < 1) {
468 if (c == 0)
469 return (scmerr(-1, "Timeout on network input"));
470 if (errno != EINTR)
471 sleep(5);
473 x = read(netfile, p, (size_t)n);
474 if (x == 0)
475 return (scmerr(-1, "Premature EOF on network input"));
476 if (x < 0)
477 return (scmerr(errno, "Read error on network"));
478 p += x;
479 n -= x;
480 m -= x;
481 bufcnt += x;
483 memcpy(data, bufptr, (size_t)count);
484 bufptr += count;
485 bufcnt -= count;
486 return (SCMOK);
489 static int
490 readcount(int *count)
491 { /* read count of data block */
492 int x;
493 int y;
494 x = readdata(sizeof(int), &y, false);
495 if (x != SCMOK)
496 return (x);
497 *count = byteswap(y);
498 return (SCMOK);
501 int
502 prereadcount(int *count)
503 { /* preread count of data block */
504 int x;
505 int y;
506 x = readdata(sizeof(int), &y, false);
507 if (x != SCMOK)
508 return (x);
509 x = readdata(sizeof(int), &y, true);
510 if (x != SCMOK)
511 return (x);
512 *count = byteswap(y);
513 return (SCMOK);
517 readflush(void)
519 return readdata(0, NULL, false);
523 readmsg(int msg)
524 { /* read header for expected message */
525 /* if message is unexpected, send back SCMHUH */
526 int x;
527 int m;
528 if (scmdebug > 1)
529 loginfo("SCM Reading message %d", msg);
530 x = readdata(sizeof(int), &m, false); /* msg type */
531 if (x != SCMOK)
532 return (x);
533 m = byteswap(m);
534 if (m == msg)
535 return (x);
537 /* check for MSGGOAWAY in case he noticed problems first */
538 if (m != MSGGOAWAY)
539 return (scmerr(-1, "Received unexpected message %d", m));
540 (void) netcrypt((char *) NULL);
541 (void) readstring(&goawayreason);
542 (void) readmend();
543 if (goawayreason == NULL)
544 return (SCMEOF);
545 logerr("SCM GOAWAY %s", goawayreason);
546 return (SCMEOF);
550 readmend(void)
552 int x;
553 int y;
554 x = readdata(sizeof(int), &y, false);
555 y = byteswap(y);
556 if (x == SCMOK && y != ENDCOUNT)
557 return (scmerr(-1, "Error reading end of message"));
558 return (x);
562 readskip(void)
563 { /* skip over one input block */
564 int x;
565 int n;
566 char buf[FILEXFER];
567 x = readcount(&n);
568 if (x != SCMOK)
569 return (x);
570 if (n < 0)
571 return (scmerr(-1, "Invalid message count %d", n));
572 while (x == SCMOK && n > 0) {
573 x = readdata((size_t)XFERSIZE(n), buf, false);
574 n -= XFERSIZE(n);
576 return (x);
579 int
580 readint(int *buf)
581 { /* read int data block */
582 int x;
583 int y;
584 x = readcount(&y);
585 if (x != SCMOK)
586 return (x);
587 if (y < 0)
588 return (scmerr(-1, "Invalid message count %d", y));
589 if (y != sizeof(int))
590 return (scmerr(-1, "Size error for int message is %d", y));
591 x = readdata(sizeof(int), &y, false);
592 (*buf) = byteswap(y);
593 if (scmdebug > 2)
594 loginfo("SCM Reading integer %d", *buf);
595 return (x);
598 int
599 readstring(char **buf)
600 { /* read string data block */
601 int x;
602 int count;
603 char *p;
605 x = readcount(&count);
606 if (x != SCMOK)
607 return (x);
608 if (count == NULLCOUNT) {
609 if (scmdebug > 2)
610 loginfo("SCM Reading string NULL");
611 *buf = NULL;
612 return (SCMOK);
614 if (count < 0)
615 return (scmerr(-1, "Invalid message count %d", count));
616 if (scmdebug > 3)
617 loginfo("SCM Reading string count %d", count);
618 if ((p = (char *) malloc((unsigned) count + 1)) == NULL)
619 return (scmerr(-1, "Can't malloc %d bytes for string", count));
620 if (cryptflag) {
621 x = getcryptbuf(count + 1);
622 if (x == SCMOK)
623 x = readdata((size_t)count, cryptbuf, false);
624 if (x != SCMOK) {
625 free(p);
626 return (x);
628 if (scmdebug > 3)
629 printf("SCM Reading encrypted string %s\n", cryptbuf);
630 decode(cryptbuf, p, count);
631 } else {
632 x = readdata((size_t)count, p, false);
633 if (x != SCMOK) {
634 free(p);
635 return (x);
638 p[count] = 0; /* NULL at end of string */
639 *buf = p;
640 if (scmdebug > 2)
641 loginfo("SCM Reading string %s", *buf);
642 return (SCMOK);
646 readfile(int f)
647 { /* read data block into open file */
648 int x;
649 int count;
650 char buf[FILEXFER];
652 if (cryptflag) {
653 x = getcryptbuf(FILEXFER);
654 if (x != SCMOK)
655 return (x);
657 x = readcount(&count);
658 if (x != SCMOK)
659 return (x);
660 if (count < 0)
661 return (scmerr(-1, "Invalid message count %d", count));
662 while (x == SCMOK && count > 0) {
663 if (cryptflag) {
664 x = readdata((size_t)XFERSIZE(count), cryptbuf, false);
665 if (x == SCMOK)
666 decode(cryptbuf, buf, XFERSIZE(count));
667 } else
668 x = readdata((size_t)XFERSIZE(count), buf, false);
669 if (x == SCMOK) {
670 (void) write(f, buf, (size_t)XFERSIZE(count));
671 count -= XFERSIZE(count);
674 return (x);
678 readmnull(int msg)
679 { /* read null message */
680 int x;
681 x = readmsg(msg);
682 if (x == SCMOK)
683 x = readmend();
684 return (x);
688 readmint(int msg, int *buf)
689 { /* read int message */
690 int x;
691 x = readmsg(msg);
692 if (x == SCMOK)
693 x = readint(buf);
694 if (x == SCMOK)
695 x = readmend();
696 return (x);
699 int
700 readmstr(int msg, char **buf)
701 { /* read string message */
702 int x;
703 x = readmsg(msg);
704 if (x == SCMOK)
705 x = readstring(buf);
706 if (x == SCMOK)
707 x = readmend();
708 return (x);
710 /**********************************
711 *** C R O S S P A T C H ***
712 **********************************/
714 void
715 crosspatch(void)
717 struct pollfd set[2];
718 int c;
719 char buf[STRINGLENGTH];
721 set[0].fd = STDIN_FILENO;
722 set[0].events = POLLIN;
723 set[1].fd = netfile;
724 set[1].events = POLLIN;
725 for (;;) {
726 if ((c = poll(set, 2, INFTIM)) < 1) {
727 if (c == -1) {
728 if (errno == EINTR) {
729 continue;
732 sleep(5);
733 continue;
735 if (set[1].revents & POLLIN) {
736 c = read(netfile, buf, sizeof(buf));
737 if (c < 0 && errno == EWOULDBLOCK)
738 c = 0;
739 else {
740 if (c <= 0) {
741 break;
743 (void) write(1, buf, (size_t)c);
746 if (set[0].revents & POLLIN) {
747 c = read(0, buf, sizeof(buf));
748 if (c < 0 && errno == EWOULDBLOCK)
749 c = 0;
750 else {
751 if (c <= 0)
752 break;
753 (void) write(netfile, buf, (size_t)c);