Qrexec common code, qubes.Filecopy common code, udev scripts
This commit is contained in:
commit
42e133b753
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
rpm/
|
||||||
|
*~
|
||||||
|
*.o
|
23
Makefile
Normal file
23
Makefile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
ifeq ($(shell uname -m),x86_64)
|
||||||
|
LIBDIR = /usr/lib64
|
||||||
|
else
|
||||||
|
LIBDIR = /usr/lib
|
||||||
|
endif
|
||||||
|
INCLUDEDIR = /usr/include
|
||||||
|
|
||||||
|
export LIBDIR INCLUDEDIR
|
||||||
|
|
||||||
|
help:
|
||||||
|
echo "Use rpmbuild to compile this pacakge"
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
||||||
|
rpms:
|
||||||
|
rpmbuild --define "_rpmdir rpm/" --define "_builddir ." -bb rpm_spec/qubes-utils.spec
|
||||||
|
all:
|
||||||
|
$(MAKE) -C qrexec-lib all
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(MAKE) -C udev install
|
||||||
|
$(MAKE) -C qrexec-lib install
|
||||||
|
|
1
Makefile.builder
Normal file
1
Makefile.builder
Normal file
@ -0,0 +1 @@
|
|||||||
|
RPM_SPEC_FILES := rpm_spec/qubes-utils.spec
|
22
qrexec-lib/Makefile
Normal file
22
qrexec-lib/Makefile
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
CC=gcc
|
||||||
|
CFLAGS+=-I. -g -Wall -pie -fPIC -Wall
|
||||||
|
COMMONIOALL=ioall.o
|
||||||
|
|
||||||
|
all: libqrexec-utils.a libqubes-rpc-filecopy.a
|
||||||
|
libqrexec-utils.a: unix-server.o ioall.o buffer.o write-stdin.o exec.o txrx-vchan.o
|
||||||
|
libqubes-rpc-filecopy.a: ioall.o copy-file.o crc32.o unpack.o
|
||||||
|
|
||||||
|
%.a:
|
||||||
|
$(AR) rcs $@ $^
|
||||||
|
clean:
|
||||||
|
rm -f *.o *~ *.a
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(DESTDIR)$(LIBDIR)
|
||||||
|
cp libqrexec-utils.a $(DESTDIR)$(LIBDIR)
|
||||||
|
cp libqubes-rpc-filecopy.a $(DESTDIR)$(LIBDIR)
|
||||||
|
mkdir -p $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
cp libqrexec-utils.h $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
cp libqubes-rpc-filecopy.h $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
cp qrexec.h $(DESTDIR)$(INCLUDEDIR)
|
||||||
|
|
99
qrexec-lib/buffer.c
Normal file
99
qrexec-lib/buffer.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "libqrexec-utils.h"
|
||||||
|
|
||||||
|
#define BUFFER_LIMIT 50000000
|
||||||
|
static int total_mem;
|
||||||
|
static char *limited_malloc(int len)
|
||||||
|
{
|
||||||
|
char *ret;
|
||||||
|
total_mem += len;
|
||||||
|
if (total_mem > BUFFER_LIMIT) {
|
||||||
|
fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = malloc(len);
|
||||||
|
if (!ret) {
|
||||||
|
perror("malloc");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void limited_free(char *ptr, int len)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
total_mem -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_init(struct buffer *b)
|
||||||
|
{
|
||||||
|
b->buflen = 0;
|
||||||
|
b->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_free(struct buffer *b)
|
||||||
|
{
|
||||||
|
if (b->buflen)
|
||||||
|
limited_free(b->data, b->buflen);
|
||||||
|
buffer_init(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following two functions can be made much more efficient.
|
||||||
|
Yet the profiling output show they are not significant CPU hogs, so
|
||||||
|
we keep them so simple to make them obviously correct.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void buffer_append(struct buffer *b, char *data, int len)
|
||||||
|
{
|
||||||
|
int newsize = len + b->buflen;
|
||||||
|
char *qdata = limited_malloc(len + b->buflen);
|
||||||
|
memcpy(qdata, b->data, b->buflen);
|
||||||
|
memcpy(qdata + b->buflen, data, len);
|
||||||
|
buffer_free(b);
|
||||||
|
b->buflen = newsize;
|
||||||
|
b->data = qdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_remove(struct buffer *b, int len)
|
||||||
|
{
|
||||||
|
int newsize = b->buflen - len;
|
||||||
|
char *qdata = limited_malloc(newsize);
|
||||||
|
memcpy(qdata, b->data + len, newsize);
|
||||||
|
buffer_free(b);
|
||||||
|
b->buflen = newsize;
|
||||||
|
b->data = qdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_len(struct buffer *b)
|
||||||
|
{
|
||||||
|
return b->buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *buffer_data(struct buffer *b)
|
||||||
|
{
|
||||||
|
return b->data;
|
||||||
|
}
|
44
qrexec-lib/copy-file.c
Normal file
44
qrexec-lib/copy-file.c
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <ioall.h>
|
||||||
|
#include "filecopy.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
|
||||||
|
extern void notify_progress(int, int);
|
||||||
|
|
||||||
|
int copy_file(int outfd, int infd, long long size, unsigned long *crc32)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
long long written = 0;
|
||||||
|
int ret;
|
||||||
|
int count;
|
||||||
|
while (written < size) {
|
||||||
|
if (size - written > sizeof(buf))
|
||||||
|
count = sizeof buf;
|
||||||
|
else
|
||||||
|
count = size - written;
|
||||||
|
ret = read(infd, buf, count);
|
||||||
|
if (!ret)
|
||||||
|
return COPY_FILE_READ_EOF;
|
||||||
|
if (ret < 0)
|
||||||
|
return COPY_FILE_READ_ERROR;
|
||||||
|
/* acumulate crc32 if requested */
|
||||||
|
if (crc32)
|
||||||
|
*crc32 = Crc32_ComputeBuf(*crc32, buf, ret);
|
||||||
|
if (!write_all(outfd, buf, ret))
|
||||||
|
return COPY_FILE_WRITE_ERROR;
|
||||||
|
notify_progress(ret, 0);
|
||||||
|
written += ret;
|
||||||
|
}
|
||||||
|
return COPY_FILE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * copy_file_status_to_str(int status)
|
||||||
|
{
|
||||||
|
switch (status) {
|
||||||
|
case COPY_FILE_OK: return "OK";
|
||||||
|
case COPY_FILE_READ_EOF: return "Unexpected end of data while reading";
|
||||||
|
case COPY_FILE_READ_ERROR: return "Error reading";
|
||||||
|
case COPY_FILE_WRITE_ERROR: return "Error writing";
|
||||||
|
default: return "????????";
|
||||||
|
}
|
||||||
|
}
|
146
qrexec-lib/crc32.c
Normal file
146
qrexec-lib/crc32.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*----------------------------------------------------------------------------*\
|
||||||
|
* CRC-32 version 2.0.0 by Craig Bruce, 2006-04-29.
|
||||||
|
*
|
||||||
|
* This program generates the CRC-32 values for the files named in the
|
||||||
|
* command-line arguments. These are the same CRC-32 values used by GZIP,
|
||||||
|
* PKZIP, and ZMODEM. The Crc32_ComputeBuf() can also be detached and
|
||||||
|
* used independently.
|
||||||
|
*
|
||||||
|
* THIS PROGRAM IS PUBLIC-DOMAIN SOFTWARE.
|
||||||
|
*
|
||||||
|
* Based on the byte-oriented implementation "File Verification Using CRC"
|
||||||
|
* by Mark R. Nelson in Dr. Dobb's Journal, May 1992, pp. 64-67.
|
||||||
|
*
|
||||||
|
* v1.0.0: original release.
|
||||||
|
* v1.0.1: fixed printf formats.
|
||||||
|
* v1.0.2: fixed something else.
|
||||||
|
* v1.0.3: replaced CRC constant table by generator function.
|
||||||
|
* v1.0.4: reformatted code, made ANSI C. 1994-12-05.
|
||||||
|
* v2.0.0: rewrote to use memory buffer & static table, 2006-04-29.
|
||||||
|
\*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*\
|
||||||
|
* Local functions
|
||||||
|
\*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||||
|
size_t bufLen );
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*\
|
||||||
|
* NAME:
|
||||||
|
* Crc32_ComputeFile() - compute CRC-32 value for a file
|
||||||
|
* DESCRIPTION:
|
||||||
|
* Computes the CRC-32 value for an opened file.
|
||||||
|
* ARGUMENTS:
|
||||||
|
* file - file pointer
|
||||||
|
* outCrc32 - (out) result CRC-32 value
|
||||||
|
* RETURNS:
|
||||||
|
* err - 0 on success or -1 on error
|
||||||
|
* ERRORS:
|
||||||
|
* - file errors
|
||||||
|
\*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int Crc32_ComputeFile( FILE *file, unsigned long *outCrc32 )
|
||||||
|
{
|
||||||
|
# define CRC_BUFFER_SIZE 8192
|
||||||
|
unsigned char buf[CRC_BUFFER_SIZE];
|
||||||
|
size_t bufLen;
|
||||||
|
|
||||||
|
/** accumulate crc32 from file **/
|
||||||
|
*outCrc32 = 0;
|
||||||
|
while (1) {
|
||||||
|
bufLen = fread( buf, 1, CRC_BUFFER_SIZE, file );
|
||||||
|
if (bufLen == 0) {
|
||||||
|
if (ferror(file)) {
|
||||||
|
fprintf( stderr, "error reading file\n" );
|
||||||
|
goto ERR_EXIT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*outCrc32 = Crc32_ComputeBuf( *outCrc32, buf, bufLen );
|
||||||
|
}
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
/** error exit **/
|
||||||
|
ERR_EXIT:
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*\
|
||||||
|
* NAME:
|
||||||
|
* Crc32_ComputeBuf() - computes the CRC-32 value of a memory buffer
|
||||||
|
* DESCRIPTION:
|
||||||
|
* Computes or accumulates the CRC-32 value for a memory buffer.
|
||||||
|
* The 'inCrc32' gives a previously accumulated CRC-32 value to allow
|
||||||
|
* a CRC to be generated for multiple sequential buffer-fuls of data.
|
||||||
|
* The 'inCrc32' for the first buffer must be zero.
|
||||||
|
* ARGUMENTS:
|
||||||
|
* inCrc32 - accumulated CRC-32 value, must be 0 on first call
|
||||||
|
* buf - buffer to compute CRC-32 value for
|
||||||
|
* bufLen - number of bytes in buffer
|
||||||
|
* RETURNS:
|
||||||
|
* crc32 - computed CRC-32 value
|
||||||
|
* ERRORS:
|
||||||
|
* (no errors are possible)
|
||||||
|
\*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||||
|
size_t bufLen )
|
||||||
|
{
|
||||||
|
static const unsigned long crcTable[256] = {
|
||||||
|
0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,
|
||||||
|
0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,
|
||||||
|
0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,
|
||||||
|
0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,
|
||||||
|
0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,
|
||||||
|
0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
|
||||||
|
0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,0x26D930AC,
|
||||||
|
0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,
|
||||||
|
0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,
|
||||||
|
0xB6662D3D,0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,
|
||||||
|
0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,
|
||||||
|
0x086D3D2D,0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
|
||||||
|
0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,
|
||||||
|
0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,0x4DB26158,0x3AB551CE,
|
||||||
|
0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,
|
||||||
|
0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
|
||||||
|
0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,
|
||||||
|
0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
|
||||||
|
0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,
|
||||||
|
0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,
|
||||||
|
0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,0xF00F9344,0x8708A3D2,0x1E01F268,
|
||||||
|
0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,
|
||||||
|
0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,
|
||||||
|
0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
|
||||||
|
0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,
|
||||||
|
0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,
|
||||||
|
0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,
|
||||||
|
0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,
|
||||||
|
0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,
|
||||||
|
0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
|
||||||
|
0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,
|
||||||
|
0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
|
||||||
|
0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,
|
||||||
|
0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,
|
||||||
|
0x47B2CF7F,0x30B5FFE9,0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,
|
||||||
|
0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
|
||||||
|
0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D };
|
||||||
|
unsigned long crc32;
|
||||||
|
unsigned char *byteBuf;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/** accumulate crc32 for buffer **/
|
||||||
|
crc32 = inCrc32 ^ 0xFFFFFFFF;
|
||||||
|
byteBuf = (unsigned char*) buf;
|
||||||
|
for (i=0; i < bufLen; i++) {
|
||||||
|
crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ byteBuf[i]) & 0xFF ];
|
||||||
|
}
|
||||||
|
return( crc32 ^ 0xFFFFFFFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*\
|
||||||
|
* END OF MODULE: crc32.c
|
||||||
|
\*----------------------------------------------------------------------------*/
|
7
qrexec-lib/crc32.h
Normal file
7
qrexec-lib/crc32.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _CRC32_H
|
||||||
|
#define _CRC32_H
|
||||||
|
|
||||||
|
extern unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||||
|
size_t bufLen );
|
||||||
|
|
||||||
|
#endif /* _CRC32_H */
|
74
qrexec-lib/exec.c
Normal file
74
qrexec-lib/exec.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern void do_exec(char *);
|
||||||
|
|
||||||
|
void fix_fds(int fdin, int fdout, int fderr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 256; i++)
|
||||||
|
if (i != fdin && i != fdout && i != fderr)
|
||||||
|
close(i);
|
||||||
|
dup2(fdin, 0);
|
||||||
|
dup2(fdout, 1);
|
||||||
|
dup2(fderr, 2);
|
||||||
|
close(fdin);
|
||||||
|
close(fdout);
|
||||||
|
if (fderr != 2)
|
||||||
|
close(fderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_fork_exec(char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
|
||||||
|
int *stderr_fd)
|
||||||
|
{
|
||||||
|
int inpipe[2], outpipe[2], errpipe[2];
|
||||||
|
|
||||||
|
if (pipe(inpipe) || pipe(outpipe) || (stderr_fd && pipe(errpipe))) {
|
||||||
|
perror("pipe");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
switch (*pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
exit(-1);
|
||||||
|
case 0:
|
||||||
|
if (stderr_fd) {
|
||||||
|
fix_fds(inpipe[0], outpipe[1], errpipe[1]);
|
||||||
|
} else
|
||||||
|
fix_fds(inpipe[0], outpipe[1], 2);
|
||||||
|
|
||||||
|
do_exec(cmdline);
|
||||||
|
exit(-1);
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
close(inpipe[0]);
|
||||||
|
close(outpipe[1]);
|
||||||
|
*stdin_fd = inpipe[1];
|
||||||
|
*stdout_fd = outpipe[0];
|
||||||
|
if (stderr_fd) {
|
||||||
|
close(errpipe[1]);
|
||||||
|
*stderr_fd = errpipe[0];
|
||||||
|
}
|
||||||
|
}
|
32
qrexec-lib/filecopy.h
Normal file
32
qrexec-lib/filecopy.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#define FILECOPY_SPOOL "/home/user/.filecopyspool"
|
||||||
|
#define FILECOPY_VMNAME_SIZE 32
|
||||||
|
#define PROGRESS_NOTIFY_DELTA (15*1000*1000)
|
||||||
|
#define MAX_PATH_LENGTH 16384
|
||||||
|
|
||||||
|
#define LEGAL_EOF 31415926
|
||||||
|
|
||||||
|
struct file_header {
|
||||||
|
unsigned int namelen;
|
||||||
|
unsigned int mode;
|
||||||
|
unsigned long long filelen;
|
||||||
|
unsigned int atime;
|
||||||
|
unsigned int atime_nsec;
|
||||||
|
unsigned int mtime;
|
||||||
|
unsigned int mtime_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct result_header {
|
||||||
|
unsigned int error_code;
|
||||||
|
unsigned long crc32;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
COPY_FILE_OK,
|
||||||
|
COPY_FILE_READ_EOF,
|
||||||
|
COPY_FILE_READ_ERROR,
|
||||||
|
COPY_FILE_WRITE_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
int copy_file(int outfd, int infd, long long size, unsigned long *crc32);
|
||||||
|
char *copy_file_status_to_str(int status);
|
||||||
|
void set_size_limit(long long new_bytes_limit, long long new_files_limit);
|
112
qrexec-lib/ioall.c
Normal file
112
qrexec-lib/ioall.c
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
void perror_wrapper(char * msg)
|
||||||
|
{
|
||||||
|
int prev=errno;
|
||||||
|
perror(msg);
|
||||||
|
errno=prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nonblock(int fd)
|
||||||
|
{
|
||||||
|
int fl = fcntl(fd, F_GETFL, 0);
|
||||||
|
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_block(int fd)
|
||||||
|
{
|
||||||
|
int fl = fcntl(fd, F_GETFL, 0);
|
||||||
|
fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_all(int fd, void *buf, int size)
|
||||||
|
{
|
||||||
|
int written = 0;
|
||||||
|
int ret;
|
||||||
|
while (written < size) {
|
||||||
|
ret = write(fd, (char *) buf + written, size - written);
|
||||||
|
if (ret == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (ret <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
written += ret;
|
||||||
|
}
|
||||||
|
// fprintf(stderr, "sent %d bytes\n", size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_all(int fd, void *buf, int size)
|
||||||
|
{
|
||||||
|
int got_read = 0;
|
||||||
|
int ret;
|
||||||
|
while (got_read < size) {
|
||||||
|
ret = read(fd, (char *) buf + got_read, size - got_read);
|
||||||
|
if (ret == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (ret == 0) {
|
||||||
|
errno = 0;
|
||||||
|
fprintf(stderr, "EOF\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno != EAGAIN)
|
||||||
|
perror_wrapper("read");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (got_read == 0) {
|
||||||
|
// force blocking operation on further reads
|
||||||
|
set_block(fd);
|
||||||
|
}
|
||||||
|
got_read += ret;
|
||||||
|
}
|
||||||
|
// fprintf(stderr, "read %d bytes\n", size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int copy_fd_all(int fdout, int fdin)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char buf[4096];
|
||||||
|
for (;;) {
|
||||||
|
ret = read(fdin, buf, sizeof(buf));
|
||||||
|
if (ret == -1 && errno == EINTR)
|
||||||
|
continue;
|
||||||
|
if (!ret)
|
||||||
|
break;
|
||||||
|
if (ret < 0) {
|
||||||
|
perror_wrapper("read");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!write_all(fdout, buf, ret)) {
|
||||||
|
perror_wrapper("write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
5
qrexec-lib/ioall.h
Normal file
5
qrexec-lib/ioall.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
int write_all(int fd, void *buf, int size);
|
||||||
|
int read_all(int fd, void *buf, int size);
|
||||||
|
int copy_fd_all(int fdout, int fdin);
|
||||||
|
void set_nonblock(int fd);
|
||||||
|
void set_block(int fd);
|
66
qrexec-lib/libqrexec-utils.h
Normal file
66
qrexec-lib/libqrexec-utils.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
* Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
|
struct buffer {
|
||||||
|
char *data;
|
||||||
|
int buflen;
|
||||||
|
};
|
||||||
|
|
||||||
|
void buffer_init(struct buffer *b);
|
||||||
|
void buffer_free(struct buffer *b);
|
||||||
|
void buffer_append(struct buffer *b, char *data, int len);
|
||||||
|
void buffer_remove(struct buffer *b, int len);
|
||||||
|
int buffer_len(struct buffer *b);
|
||||||
|
void *buffer_data(struct buffer *b);
|
||||||
|
|
||||||
|
|
||||||
|
void do_fork_exec(char *cmdline, int *pid, int *stdin_fd, int *stdout_fd,
|
||||||
|
int *stderr_fd);
|
||||||
|
int peer_server_init(int port);
|
||||||
|
char *peer_client_init(int dom, int port);
|
||||||
|
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset);
|
||||||
|
int read_ready_vchan_ext();
|
||||||
|
int read_all(int fd, void *buf, int size);
|
||||||
|
int read_all_vchan_ext(void *buf, int size);
|
||||||
|
int write_all(int fd, void *buf, int size);
|
||||||
|
int write_all_vchan_ext(void *buf, int size);
|
||||||
|
int buffer_space_vchan_ext();
|
||||||
|
void fix_fds(int fdin, int fdout, int fderr);
|
||||||
|
void set_nonblock(int fd);
|
||||||
|
void set_block(int fd);
|
||||||
|
|
||||||
|
int get_server_socket(char *);
|
||||||
|
int do_accept(int s);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
WRITE_STDIN_OK = 0x200,
|
||||||
|
WRITE_STDIN_BUFFERED,
|
||||||
|
WRITE_STDIN_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
int flush_client_data(int fd, int client_id, struct buffer *buffer);
|
||||||
|
int write_stdin(int fd, int client_id, char *data, int len,
|
||||||
|
struct buffer *buffer);
|
||||||
|
void set_nonblock(int fd);
|
||||||
|
int fork_and_flush_stdin(int fd, struct buffer *buffer);
|
68
qrexec-lib/libqubes-rpc-filecopy.h
Normal file
68
qrexec-lib/libqubes-rpc-filecopy.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
* Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBQUBES_RPC_FILECOPY_H
|
||||||
|
#define _LIBQUBES_RPC_FILECOPY_H
|
||||||
|
|
||||||
|
#define FILECOPY_VMNAME_SIZE 32
|
||||||
|
#define PROGRESS_NOTIFY_DELTA (15*1000*1000)
|
||||||
|
#define MAX_PATH_LENGTH 16384
|
||||||
|
|
||||||
|
#define LEGAL_EOF 31415926
|
||||||
|
|
||||||
|
struct file_header {
|
||||||
|
unsigned int namelen;
|
||||||
|
unsigned int mode;
|
||||||
|
unsigned long long filelen;
|
||||||
|
unsigned int atime;
|
||||||
|
unsigned int atime_nsec;
|
||||||
|
unsigned int mtime;
|
||||||
|
unsigned int mtime_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct result_header {
|
||||||
|
unsigned int error_code;
|
||||||
|
unsigned long crc32;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
COPY_FILE_OK,
|
||||||
|
COPY_FILE_READ_EOF,
|
||||||
|
COPY_FILE_READ_ERROR,
|
||||||
|
COPY_FILE_WRITE_ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
int copy_file(int outfd, int infd, long long size, unsigned long *crc32);
|
||||||
|
char *copy_file_status_to_str(int status);
|
||||||
|
void set_size_limit(long long new_bytes_limit, long long new_files_limit);
|
||||||
|
int write_all(int fd, void *buf, int size);
|
||||||
|
int read_all(int fd, void *buf, int size);
|
||||||
|
int copy_fd_all(int fdout, int fdin);
|
||||||
|
void set_nonblock(int fd);
|
||||||
|
void set_block(int fd);
|
||||||
|
|
||||||
|
extern unsigned long Crc32_ComputeBuf( unsigned long inCrc32, const void *buf,
|
||||||
|
size_t bufLen );
|
||||||
|
|
||||||
|
extern int do_unpack();
|
||||||
|
|
||||||
|
#endif /* _LIBQUBES_RPC_FILECOPY_H */
|
106
qrexec-lib/qrexec.h
Normal file
106
qrexec-lib/qrexec.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* See also http://wiki.qubes-os.org/trac/wiki/Qrexec */
|
||||||
|
|
||||||
|
#define QREXEC_DAEMON_SOCKET_DIR "/var/run/qubes"
|
||||||
|
#define MAX_FDS 256
|
||||||
|
#define MAX_DATA_CHUNK 4096
|
||||||
|
|
||||||
|
#define REXEC_PORT 512
|
||||||
|
|
||||||
|
#define QREXEC_AGENT_TRIGGER_PATH "/var/run/qubes/qrexec-agent"
|
||||||
|
#define QREXEC_AGENT_FDPASS_PATH "/var/run/qubes/qrexec-agent-fdpass"
|
||||||
|
#define MEMINFO_WRITER_PIDFILE "/var/run/meminfo-writer.pid"
|
||||||
|
#define QUBES_RPC_MULTIPLEXER_PATH "/usr/lib/qubes/qubes-rpc-multiplexer"
|
||||||
|
|
||||||
|
#define QUBES_RPC_MAGIC_CMD "QUBESRPC"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* messages from qrexec_client to qrexec_daemon (both in dom0) */
|
||||||
|
/* start process in VM and pass its stdin/out/err to dom0 */
|
||||||
|
MSG_CLIENT_TO_SERVER_EXEC_CMDLINE = 0x100,
|
||||||
|
/* start process in VM discarding its stdin/out/err (connect to /dev/null) */
|
||||||
|
MSG_CLIENT_TO_SERVER_JUST_EXEC,
|
||||||
|
/* connect to existing process in VM to receive its stdin/out/err
|
||||||
|
* struct connect_existing_params passed as data */
|
||||||
|
MSG_CLIENT_TO_SERVER_CONNECT_EXISTING,
|
||||||
|
|
||||||
|
/* messages qrexec_daemon(dom0)->qrexec_agent(VM) */
|
||||||
|
/* same as MSG_CLIENT_TO_SERVER_CONNECT_EXISTING */
|
||||||
|
MSG_SERVER_TO_AGENT_CONNECT_EXISTING,
|
||||||
|
/* same as MSG_CLIENT_TO_SERVER_EXEC_CMDLINE */
|
||||||
|
MSG_SERVER_TO_AGENT_EXEC_CMDLINE,
|
||||||
|
/* same as MSG_CLIENT_TO_SERVER_JUST_EXEC */
|
||||||
|
MSG_SERVER_TO_AGENT_JUST_EXEC,
|
||||||
|
/* pass data to process stdin */
|
||||||
|
MSG_SERVER_TO_AGENT_INPUT,
|
||||||
|
/* detach from process; qrexec_agent should close pipes to process
|
||||||
|
* stdin/out/err; it's up to the VM child process if it cause its termination */
|
||||||
|
MSG_SERVER_TO_AGENT_CLIENT_END,
|
||||||
|
|
||||||
|
/* flow control, qrexec_daemon->qrexec_agent */
|
||||||
|
/* suspend reading of named fd from child process */
|
||||||
|
MSG_XOFF,
|
||||||
|
/* resume reading of named fd from child process */
|
||||||
|
MSG_XON,
|
||||||
|
|
||||||
|
/* messages qrexec_agent(VM)->qrexec_daemon(dom0) */
|
||||||
|
/* pass data from process stdout */
|
||||||
|
MSG_AGENT_TO_SERVER_STDOUT,
|
||||||
|
/* pass data from process stderr */
|
||||||
|
MSG_AGENT_TO_SERVER_STDERR,
|
||||||
|
/* inform that process terminated and pass its exit code; this should be
|
||||||
|
* send after all data from stdout/err are send */
|
||||||
|
MSG_AGENT_TO_SERVER_EXIT_CODE,
|
||||||
|
/* call Qubes RPC service
|
||||||
|
* struct trigger_connect_params passed as data */
|
||||||
|
MSG_AGENT_TO_SERVER_TRIGGER_CONNECT_EXISTING,
|
||||||
|
|
||||||
|
/* messages qrexec_daemon->qrexec_client (both in dom0) */
|
||||||
|
/* same as MSG_AGENT_TO_SERVER_STDOUT */
|
||||||
|
MSG_SERVER_TO_CLIENT_STDOUT,
|
||||||
|
/* same as MSG_AGENT_TO_SERVER_STDERR */
|
||||||
|
MSG_SERVER_TO_CLIENT_STDERR,
|
||||||
|
/* same as MSG_AGENT_TO_SERVER_EXIT_CODE */
|
||||||
|
MSG_SERVER_TO_CLIENT_EXIT_CODE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct server_header {
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int client_id;
|
||||||
|
unsigned int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct client_header {
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct connect_existing_params {
|
||||||
|
char ident[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct trigger_connect_params {
|
||||||
|
char exec_index[64];
|
||||||
|
char target_vmname[32];
|
||||||
|
struct connect_existing_params process_fds;
|
||||||
|
};
|
221
qrexec-lib/txrx-vchan.c
Normal file
221
qrexec-lib/txrx-vchan.c
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <libvchan.h>
|
||||||
|
#include <xs.h>
|
||||||
|
#include <xenctrl.h>
|
||||||
|
|
||||||
|
static struct libvchan *ctrl;
|
||||||
|
static int is_server;
|
||||||
|
int write_all_vchan_ext(void *buf, int size)
|
||||||
|
{
|
||||||
|
int written = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (written < size) {
|
||||||
|
ret =
|
||||||
|
libvchan_write(ctrl, (char *) buf + written,
|
||||||
|
size - written);
|
||||||
|
if (ret <= 0) {
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
written += ret;
|
||||||
|
}
|
||||||
|
// fprintf(stderr, "sent %d bytes\n", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int read_all_vchan_ext(void *buf, int size)
|
||||||
|
{
|
||||||
|
int written = 0;
|
||||||
|
int ret;
|
||||||
|
while (written < size) {
|
||||||
|
ret =
|
||||||
|
libvchan_read(ctrl, (char *) buf + written,
|
||||||
|
size - written);
|
||||||
|
if (ret == 0) {
|
||||||
|
fprintf(stderr, "EOF\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
perror("read");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
written += ret;
|
||||||
|
}
|
||||||
|
// fprintf(stderr, "read %d bytes\n", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_ready_vchan_ext()
|
||||||
|
{
|
||||||
|
return libvchan_data_ready(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_space_vchan_ext()
|
||||||
|
{
|
||||||
|
return libvchan_buffer_space(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the remote domain is destroyed, we get no notification
|
||||||
|
// thus, we check for the status periodically
|
||||||
|
|
||||||
|
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||||
|
static xc_interface *xc_handle = NULL;
|
||||||
|
#else
|
||||||
|
static int xc_handle = -1;
|
||||||
|
#endif
|
||||||
|
void slow_check_for_libvchan_is_eof(struct libvchan *ctrl)
|
||||||
|
{
|
||||||
|
struct evtchn_status evst;
|
||||||
|
evst.port = ctrl->evport;
|
||||||
|
evst.dom = DOMID_SELF;
|
||||||
|
if (xc_evtchn_status(xc_handle, &evst)) {
|
||||||
|
perror("xc_evtchn_status");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (evst.status != EVTCHNSTAT_interdomain) {
|
||||||
|
fprintf(stderr, "event channel disconnected\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wait_for_vchan_or_argfd_once(int max, fd_set * rdset, fd_set * wrset)
|
||||||
|
{
|
||||||
|
int vfd, ret;
|
||||||
|
struct timespec tv = { 1, 100000000 };
|
||||||
|
sigset_t empty_set;
|
||||||
|
|
||||||
|
sigemptyset(&empty_set);
|
||||||
|
|
||||||
|
vfd = libvchan_fd_for_select(ctrl);
|
||||||
|
FD_SET(vfd, rdset);
|
||||||
|
if (vfd > max)
|
||||||
|
max = vfd;
|
||||||
|
max++;
|
||||||
|
ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno != EINTR) {
|
||||||
|
perror("select");
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
FD_ZERO(rdset);
|
||||||
|
FD_ZERO(wrset);
|
||||||
|
fprintf(stderr, "eintr\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (libvchan_is_eof(ctrl)) {
|
||||||
|
fprintf(stderr, "libvchan_is_eof\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (!is_server && ret == 0)
|
||||||
|
slow_check_for_libvchan_is_eof(ctrl);
|
||||||
|
if (FD_ISSET(vfd, rdset))
|
||||||
|
// the following will never block; we need to do this to
|
||||||
|
// clear libvchan_fd pending state
|
||||||
|
libvchan_wait(ctrl);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_for_vchan_or_argfd(int max, fd_set * rdset, fd_set * wrset)
|
||||||
|
{
|
||||||
|
fd_set r = *rdset, w = *wrset;
|
||||||
|
do {
|
||||||
|
*rdset = r;
|
||||||
|
*wrset = w;
|
||||||
|
}
|
||||||
|
while (wait_for_vchan_or_argfd_once(max, rdset, wrset) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int peer_server_init(int port)
|
||||||
|
{
|
||||||
|
is_server = 1;
|
||||||
|
ctrl = libvchan_server_init(port);
|
||||||
|
if (!ctrl) {
|
||||||
|
perror("libvchan_server_init");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *peer_client_init(int dom, int port)
|
||||||
|
{
|
||||||
|
struct xs_handle *xs;
|
||||||
|
char buf[64];
|
||||||
|
char *name;
|
||||||
|
char *dummy;
|
||||||
|
unsigned int len = 0;
|
||||||
|
char devbuf[128];
|
||||||
|
unsigned int count;
|
||||||
|
char **vec;
|
||||||
|
|
||||||
|
// double_buffered = 1; // writes to vchan are buffered, nonblocking
|
||||||
|
// double_buffer_init();
|
||||||
|
xs = xs_daemon_open();
|
||||||
|
if (!xs) {
|
||||||
|
perror("xs_daemon_open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
snprintf(buf, sizeof(buf), "/local/domain/%d/name", dom);
|
||||||
|
name = xs_read(xs, 0, buf, &len);
|
||||||
|
if (!name) {
|
||||||
|
perror("xs_read domainname");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
snprintf(devbuf, sizeof(devbuf),
|
||||||
|
"/local/domain/%d/device/vchan/%d/event-channel", dom,
|
||||||
|
port);
|
||||||
|
xs_watch(xs, devbuf, devbuf);
|
||||||
|
do {
|
||||||
|
vec = xs_read_watch(xs, &count);
|
||||||
|
if (vec)
|
||||||
|
free(vec);
|
||||||
|
len = 0;
|
||||||
|
dummy = xs_read(xs, 0, devbuf, &len);
|
||||||
|
}
|
||||||
|
while (!dummy || !len); // wait for the server to create xenstore entries
|
||||||
|
free(dummy);
|
||||||
|
xs_daemon_close(xs);
|
||||||
|
|
||||||
|
// now client init should succeed; "while" is redundant
|
||||||
|
while (!(ctrl = libvchan_client_init(dom, port)));
|
||||||
|
|
||||||
|
#ifdef XENCTRL_HAS_XC_INTERFACE
|
||||||
|
xc_handle = xc_interface_open(NULL, 0, 0);
|
||||||
|
if (!xc_handle) {
|
||||||
|
#else
|
||||||
|
xc_handle = xc_interface_open();
|
||||||
|
if (xc_handle < 0) {
|
||||||
|
#endif
|
||||||
|
perror("xc_interface_open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
68
qrexec-lib/unix-server.c
Normal file
68
qrexec-lib/unix-server.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
//#include "qrexec.h"
|
||||||
|
|
||||||
|
int get_server_socket(char *socket_address)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sockname;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
unlink(socket_address);
|
||||||
|
|
||||||
|
s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
memset(&sockname, 0, sizeof(sockname));
|
||||||
|
sockname.sun_family = AF_UNIX;
|
||||||
|
memcpy(sockname.sun_path, socket_address, strlen(socket_address));
|
||||||
|
|
||||||
|
if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) {
|
||||||
|
printf("bind() failed\n");
|
||||||
|
close(s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// chmod(sockname.sun_path, 0666);
|
||||||
|
if (listen(s, 5) == -1) {
|
||||||
|
perror("listen() failed\n");
|
||||||
|
close(s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_accept(int s)
|
||||||
|
{
|
||||||
|
struct sockaddr_un peer;
|
||||||
|
unsigned int addrlen;
|
||||||
|
int fd;
|
||||||
|
addrlen = sizeof(peer);
|
||||||
|
fd = accept(s, (struct sockaddr *) &peer, &addrlen);
|
||||||
|
if (fd == -1) {
|
||||||
|
perror("unix accept");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
157
qrexec-lib/unpack.c
Normal file
157
qrexec-lib/unpack.c
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#define _GNU_SOURCE /* For O_NOFOLLOW. */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ioall.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "filecopy.h"
|
||||||
|
#include "crc32.h"
|
||||||
|
|
||||||
|
char untrusted_namebuf[MAX_PATH_LENGTH];
|
||||||
|
long long bytes_limit = 0;
|
||||||
|
long long files_limit = 0;
|
||||||
|
long long total_bytes = 0;
|
||||||
|
long long total_files = 0;
|
||||||
|
|
||||||
|
void set_size_limit(long long new_bytes_limit, long long new_files_limit)
|
||||||
|
{
|
||||||
|
bytes_limit = new_bytes_limit;
|
||||||
|
files_limit = new_files_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long crc32_sum = 0;
|
||||||
|
int read_all_with_crc(int fd, void *buf, int size) {
|
||||||
|
int ret;
|
||||||
|
ret = read_all(fd, buf, size);
|
||||||
|
if (ret)
|
||||||
|
crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_status_and_crc(int code) {
|
||||||
|
struct result_header hdr;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
saved_errno = errno;
|
||||||
|
hdr.error_code = code;
|
||||||
|
hdr.crc32 = crc32_sum;
|
||||||
|
if (!write_all(1, &hdr, sizeof(hdr)))
|
||||||
|
perror("write status");
|
||||||
|
errno = saved_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_exit(int code)
|
||||||
|
{
|
||||||
|
close(0);
|
||||||
|
send_status_and_crc(code);
|
||||||
|
exit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fix_times_and_perms(struct file_header *untrusted_hdr,
|
||||||
|
char *untrusted_name)
|
||||||
|
{
|
||||||
|
struct timeval times[2] =
|
||||||
|
{ {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
|
||||||
|
{untrusted_hdr->mtime,
|
||||||
|
untrusted_hdr->mtime_nsec / 1000}
|
||||||
|
};
|
||||||
|
if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
|
||||||
|
do_exit(errno);
|
||||||
|
if (utimes(untrusted_name, times)) /* as above */
|
||||||
|
do_exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void process_one_file_reg(struct file_header *untrusted_hdr,
|
||||||
|
char *untrusted_name)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */
|
||||||
|
if (fdout < 0)
|
||||||
|
do_exit(errno);
|
||||||
|
total_bytes += untrusted_hdr->filelen;
|
||||||
|
if (bytes_limit && total_bytes > bytes_limit)
|
||||||
|
do_exit(EDQUOT);
|
||||||
|
ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
|
||||||
|
if (ret != COPY_FILE_OK) {
|
||||||
|
if (ret == COPY_FILE_READ_EOF
|
||||||
|
|| ret == COPY_FILE_READ_ERROR)
|
||||||
|
do_exit(LEGAL_EOF); // hopefully remote will produce error message
|
||||||
|
else
|
||||||
|
do_exit(errno);
|
||||||
|
}
|
||||||
|
close(fdout);
|
||||||
|
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void process_one_file_dir(struct file_header *untrusted_hdr,
|
||||||
|
char *untrusted_name)
|
||||||
|
{
|
||||||
|
// fix perms only when the directory is sent for the second time
|
||||||
|
// it allows to transfer r.x directory contents, as we create it rwx initially
|
||||||
|
if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
|
||||||
|
return;
|
||||||
|
if (errno != EEXIST)
|
||||||
|
do_exit(errno);
|
||||||
|
fix_times_and_perms(untrusted_hdr, untrusted_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_one_file_link(struct file_header *untrusted_hdr,
|
||||||
|
char *untrusted_name)
|
||||||
|
{
|
||||||
|
char untrusted_content[MAX_PATH_LENGTH];
|
||||||
|
unsigned int filelen;
|
||||||
|
if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
|
||||||
|
do_exit(ENAMETOOLONG);
|
||||||
|
filelen = untrusted_hdr->filelen; /* sanitized above */
|
||||||
|
if (!read_all_with_crc(0, untrusted_content, filelen))
|
||||||
|
do_exit(LEGAL_EOF); // hopefully remote has produced error message
|
||||||
|
untrusted_content[filelen] = 0;
|
||||||
|
if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
|
||||||
|
do_exit(errno);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_one_file(struct file_header *untrusted_hdr)
|
||||||
|
{
|
||||||
|
unsigned int namelen;
|
||||||
|
if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
|
||||||
|
do_exit(ENAMETOOLONG);
|
||||||
|
namelen = untrusted_hdr->namelen; /* sanitized above */
|
||||||
|
if (!read_all_with_crc(0, untrusted_namebuf, namelen))
|
||||||
|
do_exit(LEGAL_EOF); // hopefully remote has produced error message
|
||||||
|
untrusted_namebuf[namelen] = 0;
|
||||||
|
if (S_ISREG(untrusted_hdr->mode))
|
||||||
|
process_one_file_reg(untrusted_hdr, untrusted_namebuf);
|
||||||
|
else if (S_ISLNK(untrusted_hdr->mode))
|
||||||
|
process_one_file_link(untrusted_hdr, untrusted_namebuf);
|
||||||
|
else if (S_ISDIR(untrusted_hdr->mode))
|
||||||
|
process_one_file_dir(untrusted_hdr, untrusted_namebuf);
|
||||||
|
else
|
||||||
|
do_exit(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_unpack()
|
||||||
|
{
|
||||||
|
struct file_header untrusted_hdr;
|
||||||
|
/* initialize checksum */
|
||||||
|
crc32_sum = 0;
|
||||||
|
while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
|
||||||
|
/* check for end of transfer marker */
|
||||||
|
if (untrusted_hdr.namelen == 0) {
|
||||||
|
errno = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
process_one_file(&untrusted_hdr);
|
||||||
|
total_files++;
|
||||||
|
if (files_limit && total_files > files_limit)
|
||||||
|
do_exit(EDQUOT);
|
||||||
|
}
|
||||||
|
send_status_and_crc(errno);
|
||||||
|
return errno;
|
||||||
|
}
|
135
qrexec-lib/write-stdin.c
Normal file
135
qrexec-lib/write-stdin.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* The Qubes OS Project, http://www.qubes-os.org
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Rafal Wojtczuk <rafal@invisiblethingslab.com>
|
||||||
|
*
|
||||||
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "qrexec.h"
|
||||||
|
#include "libqrexec-utils.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
There is buffered data in "buffer" for client id "client_id", and select()
|
||||||
|
reports that "fd" is writable. Write as much as possible to fd, if all sent,
|
||||||
|
notify the peer that this client's pipe is no longer full.
|
||||||
|
*/
|
||||||
|
int flush_client_data(int fd, int client_id, struct buffer *buffer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int len;
|
||||||
|
for (;;) {
|
||||||
|
len = buffer_len(buffer);
|
||||||
|
if (len > MAX_DATA_CHUNK)
|
||||||
|
len = MAX_DATA_CHUNK;
|
||||||
|
ret = write(fd, buffer_data(buffer), len);
|
||||||
|
if (ret == -1) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
return WRITE_STDIN_ERROR;
|
||||||
|
} else
|
||||||
|
return WRITE_STDIN_BUFFERED;
|
||||||
|
}
|
||||||
|
// we previously called buffer_remove(buffer, len)
|
||||||
|
// it will be wrong if we change MAX_DATA_CHUNK to something large
|
||||||
|
// as pipes writes are atomic only to PIPE_MAX limit
|
||||||
|
buffer_remove(buffer, ret);
|
||||||
|
len = buffer_len(buffer);
|
||||||
|
if (!len) {
|
||||||
|
struct server_header s_hdr;
|
||||||
|
s_hdr.type = MSG_XON;
|
||||||
|
s_hdr.client_id = client_id;
|
||||||
|
s_hdr.len = 0;
|
||||||
|
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
|
||||||
|
return WRITE_STDIN_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Write "len" bytes from "data" to "fd". If not all written, buffer the rest
|
||||||
|
to "buffer", and notify the peer that the client "client_id" pipe is full via
|
||||||
|
MSG_XOFF message.
|
||||||
|
*/
|
||||||
|
int write_stdin(int fd, int client_id, char *data, int len,
|
||||||
|
struct buffer *buffer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
if (buffer_len(buffer)) {
|
||||||
|
buffer_append(buffer, data, len);
|
||||||
|
return WRITE_STDIN_BUFFERED;
|
||||||
|
}
|
||||||
|
while (written < len) {
|
||||||
|
ret = write(fd, data + written, len - written);
|
||||||
|
if (ret == 0) {
|
||||||
|
perror("write_stdin: write returns 0 ???");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ret == -1) {
|
||||||
|
struct server_header s_hdr;
|
||||||
|
|
||||||
|
if (errno != EAGAIN)
|
||||||
|
return WRITE_STDIN_ERROR;
|
||||||
|
|
||||||
|
buffer_append(buffer, data + written,
|
||||||
|
len - written);
|
||||||
|
|
||||||
|
s_hdr.type = MSG_XOFF;
|
||||||
|
s_hdr.client_id = client_id;
|
||||||
|
s_hdr.len = 0;
|
||||||
|
write_all_vchan_ext(&s_hdr, sizeof s_hdr);
|
||||||
|
|
||||||
|
return WRITE_STDIN_BUFFERED;
|
||||||
|
}
|
||||||
|
written += ret;
|
||||||
|
}
|
||||||
|
return WRITE_STDIN_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Data feed process has exited, so we need to clear all control structures for
|
||||||
|
the client. However, if we have buffered data for the client (which is rare btw),
|
||||||
|
fire&forget a separate process to flush them.
|
||||||
|
*/
|
||||||
|
int fork_and_flush_stdin(int fd, struct buffer *buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!buffer_len(buffer))
|
||||||
|
return 0;
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
for (i = 0; i < MAX_FDS; i++)
|
||||||
|
if (i != fd && i != 2)
|
||||||
|
close(i);
|
||||||
|
set_block(fd);
|
||||||
|
write_all(fd, buffer_data(buffer), buffer_len(buffer));
|
||||||
|
exit(0);
|
||||||
|
}
|
54
rpm_spec/qubes-utils.spec
Normal file
54
rpm_spec/qubes-utils.spec
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
%define version %(cat version)
|
||||||
|
%if 0%{?qubes_builder}
|
||||||
|
%define _builddir %(pwd)
|
||||||
|
%endif
|
||||||
|
|
||||||
|
Name: qubes-utils
|
||||||
|
Version: %{version}
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: Common Linux files for Qubes Dom0 and VM
|
||||||
|
|
||||||
|
Group: Qubes
|
||||||
|
License: GPL
|
||||||
|
URL: http://www.qubes-os.org
|
||||||
|
|
||||||
|
Requires: udev
|
||||||
|
|
||||||
|
%description
|
||||||
|
Common Linux files for Qubes Dom0 and VM
|
||||||
|
|
||||||
|
%package devel
|
||||||
|
Summary: Development headers for qubes-utils
|
||||||
|
Release: 1%{?dist}
|
||||||
|
|
||||||
|
%description devel
|
||||||
|
Development header and files for qubes-utils
|
||||||
|
|
||||||
|
%prep
|
||||||
|
|
||||||
|
|
||||||
|
%build
|
||||||
|
make all
|
||||||
|
|
||||||
|
%install
|
||||||
|
make install DESTDIR=%{buildroot}
|
||||||
|
|
||||||
|
%clean
|
||||||
|
rm -rf $RPM_BUILD_ROOT
|
||||||
|
|
||||||
|
%files
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
/etc/udev/rules.d/99-qubes-*.rules
|
||||||
|
/usr/libexec/qubes/udev-*
|
||||||
|
|
||||||
|
|
||||||
|
%files devel
|
||||||
|
%defattr(-,root,root,-)
|
||||||
|
/usr/include/libqrexec-utils.h
|
||||||
|
/usr/include/libqubes-rpc-filecopy.h
|
||||||
|
/usr/include/qrexec.h
|
||||||
|
%{_libdir}/libqrexec-utils.a
|
||||||
|
%{_libdir}/libqubes-rpc-filecopy.a
|
||||||
|
|
||||||
|
%changelog
|
||||||
|
|
13
udev/Makefile
Normal file
13
udev/Makefile
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
all:
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p $(DESTDIR)/etc/udev/rules.d
|
||||||
|
cp udev-qubes-block.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-block.rules
|
||||||
|
cp udev-qubes-usb.rules $(DESTDIR)/etc/udev/rules.d/99-qubes-usb.rules
|
||||||
|
|
||||||
|
mkdir -p $(DESTDIR)/usr/libexec/qubes
|
||||||
|
cp udev-block-add-change $(DESTDIR)/usr/libexec/qubes/
|
||||||
|
cp udev-block-remove $(DESTDIR)/usr/libexec/qubes/
|
||||||
|
cp udev-block-cleanup $(DESTDIR)/usr/libexec/qubes/
|
||||||
|
cp udev-usb-add-change $(DESTDIR)/usr/libexec/qubes/
|
||||||
|
cp udev-usb-remove $(DESTDIR)/usr/libexec/qubes/
|
61
udev/udev-block-add-change
Executable file
61
udev/udev-block-add-change
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
NAME=${DEVNAME#/dev/}
|
||||||
|
DESC="${ID_MODEL} (${ID_FS_LABEL})"
|
||||||
|
SIZE=$[ $(cat /sys/$DEVPATH/size) * 512 ]
|
||||||
|
MODE=w
|
||||||
|
XS_KEY="qubes-block-devices/$NAME"
|
||||||
|
|
||||||
|
xs_remove() {
|
||||||
|
if [ "$QUBES_EXPOSED" == "1" ]; then
|
||||||
|
xenstore-rm "$XS_KEY"
|
||||||
|
fi
|
||||||
|
echo QUBES_EXPOSED=0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ignore mounted...
|
||||||
|
if fgrep -q $DEVNAME /proc/mounts; then
|
||||||
|
xs_remove
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# ... and used by device-mapper
|
||||||
|
if [ -n "`ls -A /sys/$DEVPATH/holders 2> /dev/null`" ]; then
|
||||||
|
xs_remove
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# ... and "empty" loop devices
|
||||||
|
if [ "$MAJOR" -eq 7 -a ! -d /sys/$DEVPATH/loop ]; then
|
||||||
|
xs_remove
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Special case for CD
|
||||||
|
if [ "$ID_TYPE" = "cd" ]; then
|
||||||
|
if [ "$ID_CDROM_MEDIA" != "1" ]; then
|
||||||
|
# Hide empty cdrom drive
|
||||||
|
xs_remove
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
MODE=r
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Special description for loop devices
|
||||||
|
if [ -d /sys/$DEVPATH/loop ]; then
|
||||||
|
DESC=$(cat /sys/$DEVPATH/loop/backing_file)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get lock only in dom0 - there are so many block devices so it causes xenstore
|
||||||
|
# deadlocks sometimes.
|
||||||
|
if [ -f /etc/qubes-release ]; then
|
||||||
|
# Skip xenstore-write if cannot obtain lock. This can mean very early system startup
|
||||||
|
# stage without /run mounted (or populated). Devices will be rediscovered later
|
||||||
|
# by qubes-core startup script.
|
||||||
|
exec 9>>/var/run/qubes/block-xenstore.lock || exit 0
|
||||||
|
flock 9
|
||||||
|
fi
|
||||||
|
|
||||||
|
xenstore-write "$XS_KEY/desc" "$DESC" "$XS_KEY/size" "$SIZE" "$XS_KEY/mode" "$MODE"
|
||||||
|
echo QUBES_EXPOSED=1
|
||||||
|
|
||||||
|
# Make sure that block backend is loaded
|
||||||
|
/sbin/modprobe xen-blkback 2> /dev/null || /sbin/modprobe blkbk
|
8
udev/udev-block-cleanup
Executable file
8
udev/udev-block-cleanup
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
DEVID=$[ $MAJOR * 256 + $MINOR ]
|
||||||
|
|
||||||
|
XS_PATH="device/vbd/$DEVID"
|
||||||
|
|
||||||
|
# Double check that DEVID is not empty
|
||||||
|
[ -n "$DEVID" ] && xenstore-rm $XS_PATH
|
32
udev/udev-block-remove
Executable file
32
udev/udev-block-remove
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
NAME=${DEVNAME#/dev/}
|
||||||
|
XS_KEY="qubes-block-devices/$NAME"
|
||||||
|
xenstore-rm "$XS_KEY"
|
||||||
|
|
||||||
|
# If device was connected to some VM - detach it
|
||||||
|
# Notice: this can be run also in VM, so we cannot use xl...
|
||||||
|
|
||||||
|
device_detach() {
|
||||||
|
xs_path=$1
|
||||||
|
|
||||||
|
xenstore-write $xs_path/online 0 $xs_path/state 5
|
||||||
|
|
||||||
|
# Wait for backend to finish dev shutdown
|
||||||
|
try=30
|
||||||
|
# -lt will break loop also when 'state' will be empty
|
||||||
|
while [ "`xenstore-read $xs_path/state 2> /dev/null`" -lt 6 ]; do
|
||||||
|
try=$[ $try - 1 ]
|
||||||
|
[ "$try" -le 0 ] && break
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
xenstore-rm $xs_path
|
||||||
|
}
|
||||||
|
|
||||||
|
for XS_DEV_PATH in `xenstore-ls -f backend/vbd | grep 'backend/vbd/[0-9]*/[0-9]* ' | cut -f 1 -d ' '`; do
|
||||||
|
CUR_DEVICE=`xenstore-read "$XS_DEV_PATH/params"`
|
||||||
|
if [ "$CUR_DEVICE" == "$DEVNAME" ]; then
|
||||||
|
device_detach "$XS_DEV_PATH"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
20
udev/udev-qubes-block.rules
Normal file
20
udev/udev-qubes-block.rules
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Expose all (except xen-frontend) block devices via xenstore
|
||||||
|
|
||||||
|
# Only block devices are interesting
|
||||||
|
SUBSYSTEM!="block", GOTO="qubes_block_end"
|
||||||
|
|
||||||
|
# Skip xen-blkfront devices
|
||||||
|
ENV{MAJOR}=="202", GOTO="qubes_block_end"
|
||||||
|
|
||||||
|
# Skip device-mapper devices
|
||||||
|
ENV{MAJOR}=="253", GOTO="qubes_block_end"
|
||||||
|
|
||||||
|
IMPORT{db}="QUBES_EXPOSED"
|
||||||
|
ACTION=="add", IMPORT{program}="/usr/libexec/qubes/udev-block-add-change"
|
||||||
|
ACTION=="change", IMPORT{program}="/usr/libexec/qubes/udev-block-add-change"
|
||||||
|
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-block-remove"
|
||||||
|
|
||||||
|
LABEL="qubes_block_end"
|
||||||
|
|
||||||
|
# Cleanup disconnected frontend from xenstore
|
||||||
|
ACTION=="remove", SUBSYSTEM=="block", ENV{MAJOR}=="202", RUN+="/usr/libexec/qubes/udev-block-cleanup"
|
10
udev/udev-qubes-usb.rules
Normal file
10
udev/udev-qubes-usb.rules
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Expose all USB devices (except block) via xenstore
|
||||||
|
|
||||||
|
# Handle only USB devices
|
||||||
|
SUBSYSTEM!="usb", GOTO="qubes_usb_end"
|
||||||
|
|
||||||
|
ACTION=="add", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
|
||||||
|
ACTION=="change", IMPORT{program}="/usr/libexec/qubes/udev-usb-add-change"
|
||||||
|
ACTION=="remove", RUN+="/usr/libexec/qubes/udev-usb-remove"
|
||||||
|
|
||||||
|
LABEL="qubes_usb_end"
|
40
udev/udev-usb-add-change
Executable file
40
udev/udev-usb-add-change
Executable file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
##
|
||||||
|
## This script is invoked by udev rules whenever USB device appears or
|
||||||
|
## changes. This happens in usbvm domain (or dom0 if USB controller
|
||||||
|
## drivers are in dom0). The script records information about available
|
||||||
|
## USB devices into XS directory, making it available to qvm-usb tool
|
||||||
|
## running in dom0.
|
||||||
|
##
|
||||||
|
|
||||||
|
# FIXME: Ignore USB hubs and other wierd devices (see also in udev-usb-remove).
|
||||||
|
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
|
||||||
|
[ "$DEVTYPE" != "usb_device" ] && exit 0
|
||||||
|
|
||||||
|
# xenstore doesn't allow dot in key name
|
||||||
|
XSNAME=`basename ${DEVPATH} | tr . _`
|
||||||
|
|
||||||
|
# FIXME: For some devices (my Cherry keyboard) ID_SERIAL does not
|
||||||
|
# contain proper human-readable name, should find better method to
|
||||||
|
# build devide description.
|
||||||
|
#DESC=`python -c "dev='%d-%d' % (int('${BUSNUM}'.lstrip('0')), (int('${DEVNUM}'.lstrip('0'))-1)); from xen.util import vusb_util; print vusb_util.get_usbdevice_info(dev);"`
|
||||||
|
DESC="${ID_VENDOR_ID}:${ID_MODEL_ID} ${ID_SERIAL}"
|
||||||
|
|
||||||
|
VERSION=`cat /sys/$DEVPATH/version`
|
||||||
|
if [ "${VERSION}" = " 1.00" -o "${VERSION}" = " 1.10" ] ; then
|
||||||
|
VERSION=1
|
||||||
|
elif [ "${VERSION}" = " 2.00" ] ; then
|
||||||
|
VERSION=2
|
||||||
|
else
|
||||||
|
# FIXME: silently ignoring devices with unexpected USB version
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
XS_KEY="qubes-usb-devices/$XSNAME"
|
||||||
|
|
||||||
|
xenstore-write "$XS_KEY/desc" "$DESC"
|
||||||
|
xenstore-write "$XS_KEY/usb-ver" "$VERSION"
|
||||||
|
|
||||||
|
# Make sure PVUSB backend driver is loaded.
|
||||||
|
/sbin/modprobe xen-usbback 2> /dev/null || /sbin/modprobe usbbk
|
9
udev/udev-usb-remove
Executable file
9
udev/udev-usb-remove
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# FIXME: Ignore USB hubs.
|
||||||
|
[ "`echo $TYPE | cut -f1 -d/`" = "9" ] && exit 0
|
||||||
|
|
||||||
|
NAME=`basename ${DEVPATH} | tr . _`
|
||||||
|
XS_KEY="qubes-usb-devices/$NAME"
|
||||||
|
|
||||||
|
xenstore-rm "$XS_KEY"
|
Loading…
Reference in New Issue
Block a user