1 /*
2  *  probe_vnc.c
3  *
4  *  Copyright (C) Brian de Alwis 2004
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *
8  *  transcode is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  transcode is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GNU Make; see the file COPYING.  If not, write to
20  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #include "transcode.h"
25 #include "tcinfo.h"
26 #include "ioaux.h"
27 #include "tc.h"
28 #include "libtc/libtc.h"
29 
30 
31 /* Some VNC constants */
32 #define VNCREC_MAGIC_STRING	"vncLog0.0"
33 #define VNCREC_MAGIC_SIZE	(9)
34 #define VNC_RFB_PROTOCOL_SCANF_FORMAT "RFB %03d.%03d\n"
35 #define VNC_RFB_PROTO_VERSION_SIZE	(12)
36 
37 #define VNC33_CHALLENGESIZE	(16)
38 
39 #define VNC33_rfbConnFailed	(0)
40 #define VNC33_rfbNoAuth		(1)
41 #define VNC33_rfbVncAuth	(2)
42 
43 #define VNC33_rfbVncAuthOK	(0)
44 #define VNC33_rfbVncAuthFailed	(1)
45 #define VNC33_rfbVncAuthTooMany	(2)
46 
47 /*
48    RFB 3.X protocol is as follows (from vncrec source code):
49     * server send 12-byte (SIZE_SIZE_RFB_PROTO_VERSION) header
50       encoding the RFB version as an ASCII string
51     * server sends 4-byte number (big-endian) to alert auth
52       requirements
53     * if requiring auth, server then sends 16-byte (VNC33_CHALLENGESIZE)
54       packet, which is to be encrypted and sent back (same size).
55       The server then sends 32-bit word result on pass-fail.  Entire
56       thing aborted if not passed.
57     * client sends 1-byte message
58     * server then sends a display-paramters message, containing
59       (in order) the width (2-byte), height (2-byte), preferred pixel
60       format (1-byte), and desktop name (1-byte with length, n bytes).
61  */
62 
probe_vnc(info_t * ipipe)63 void probe_vnc(info_t *ipipe)
64 {
65     unsigned char buf[100];
66     unsigned char matchingBuffer[100];
67     int index = 0, major, minor, authReqs;
68     int width, height;
69 
70     if(tc_pread(ipipe->fd_in, buf, sizeof(buf)) != sizeof(buf)) {
71 	tc_log_error(__FILE__, "end of stream");
72 	ipipe->error=1;
73 	return;
74     }
75 
76     /* Check VNCREC magic */
77     ac_memcpy(matchingBuffer, &buf[index], VNCREC_MAGIC_SIZE);
78     matchingBuffer[VNCREC_MAGIC_SIZE] = 0;
79     if(strcmp(matchingBuffer, VNCREC_MAGIC_STRING)) { /* NOT EQUAL */
80 	tc_log_error(__FILE__, "unsupported version of vncrec (\"%s\")",
81 	             matchingBuffer);
82 	ipipe->error=1;
83 	return;
84     }
85     index += VNCREC_MAGIC_SIZE;
86 
87 
88     /* Ensure RFB protocol is valid */
89     ac_memcpy(matchingBuffer, &buf[index], VNC_RFB_PROTO_VERSION_SIZE);
90     matchingBuffer[VNC_RFB_PROTO_VERSION_SIZE] = 0;
91     if(sscanf(matchingBuffer, VNC_RFB_PROTOCOL_SCANF_FORMAT, &major, &minor) != 2) {
92 	tc_log_error(__FILE__, "unknown RFB protocol (\"%s\")",
93 	             matchingBuffer);
94 	ipipe->error=1;
95 	return;
96     }
97     if (ipipe->verbose & TC_DEBUG) {
98 	tc_log_msg(__FILE__, "File recorded as RFB Protocol v%d.%d",
99 	           major, minor);
100     }
101     if(major != 3) {
102 	tc_log_error(__FILE__, "unsupported RFB protocol (only support v3)");
103 	ipipe->error=1;
104 	return;
105     }
106     index += VNC_RFB_PROTO_VERSION_SIZE;
107 
108     /* Check authentication requirements */
109     authReqs = (buf[index] << 24) | (buf[index+1] << 16)
110 		| (buf[index+2] << 8) | buf[index+3];
111     index += 4;
112     switch(authReqs) {
113       case VNC33_rfbNoAuth:
114 	if (ipipe->verbose & TC_DEBUG)
115 	    tc_log_msg(__FILE__, "No authorization required.");
116 	break;
117 
118       case VNC33_rfbVncAuth: {
119 	int authResp =
120 	index += VNC33_CHALLENGESIZE;
121 	authResp = (buf[index] << 24) | (buf[index+1] << 16)
122 		    | (buf[index+2] << 8) | buf[index+3];
123 	/* switch(authResp) { ... } */
124 	index += 4;
125 	break;
126 	}
127 
128       case VNC33_rfbConnFailed:
129       default:
130 	tc_log_error(__FILE__, "apparently connection failed?");
131 	ipipe->error=1;
132 	return;
133     }
134 
135     /* Receive display parameters */
136     width = (buf[index] << 8) | buf[index+1];
137     height = (buf[index+2] << 8) | buf[index+3];
138 
139     ipipe->probe_info->width  = width;
140     ipipe->probe_info->height = height;
141     ipipe->probe_info->fps = 25.;
142     ipipe->probe_info->frc = 3;
143     ipipe->probe_info->codec = TC_CODEC_RGB;
144     ipipe->probe_info->magic = ipipe->magic;
145 
146 }
147