Система трансляции экранов компьютеров учеников на доску
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
doskast/webserver/doskast-trigger-connect.c

181 lines
4.2 KiB

#include <ctype.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
// https://abf.io/import/cgilib
#include <cgi.h>
// https://abf.io/import/fcgi
#include <fcgios.h>
#include <fcgi_stdio.h>
// allow to redefine as gcc -D...
#ifndef DIR
#define DIR "/tmp"
#endif
#define HTTP_OK 200
#define HTTP_BAD_REQUEST 400
#define HTTP_ERROR 500
/* Here we could verify validity of a IPv4 or IPv6 address,
* but that is very complex. Just sanitize input. */
int
_verify_ip(char *ip){
int rc = 0;
for (int i = 0; i < strlen(ip); i++){
if (!( (ip[i] == '.') || /* IPv4 dots */
(ip[i] == ':') || /* IPv6 */
(ip[i] == '/') || /* XXX Is it needed for IPv6? */
(isalnum(ip[i]) != 0) /* Numbers (v4 and v6) and letters (v6) */
)) {
rc = 1;
break;
}
}
return rc;
}
int
_verify_geometry(char *value){
int rc = 0;
for (int i = 0; i < strlen(value); i++){
if (isdigit(value[i]) == 0) {
rc = 1;
break;
}
}
return rc;
}
/* Generate a random alphanum sequence
* Example: 10841ee0cc4f (12 chars) */
int
_rand(char **rs){
// https://books.google.ru/books?id=1nG3BwAAQBAJ
// hex.data will be 6x2=12 chars
unsigned char buf_rnd[6];
gnutls_datum_t rnd = { buf_rnd, sizeof(buf_rnd) };
int rc;
rc = gnutls_rnd(GNUTLS_RND_NONCE, rnd.data, rnd.size);
if (rc != GNUTLS_E_SUCCESS) {
fprintf(stderr, "Error in gnutls_rnd()\n");
goto out;
}
gnutls_datum_t hex;
rc = gnutls_hex_encode2(&rnd, &hex);
if (rc != GNUTLS_E_SUCCESS) {
fprintf(stderr, "Error in gnutls_hex_encode2()\n");
goto out;
}
*rs = malloc(hex.size);
rc = sprintf(*rs, "%s", hex.data);
if (rc < 0) {
fprintf(stderr, "Error in sprintf()\n");
goto out;
}
out:
return rc;
}
int
main(){
int rc = 0;
int http_code = HTTP_ERROR;
// text of errors which must be seen by people
char *error_msg;
if (access(DIR, W_OK) != 0) {
fprintf(stderr, "Directory %s does not exist or is not writable\n", DIR);
goto out;
}
// first chdir() and then chroot()!
if (!( chdir(DIR) == 0 && chroot(DIR) == 0 )) {
fprintf(stderr, "Cannot chdir and chroot into %s\n", DIR);
goto out;
}
s_cgi *cgi;
while(FCGI_Accept() >= 0) {
// cgiReadVariables() returns NULL if QUESRY_STRING is empty,
// and it is empty when neither width not height are defined,
// so checking its return value is useless.
cgi = cgiInit();
char *ip = getenv("REMOTE_ADDR");
if (ip == NULL) {
fprintf(stderr, "Env REMOTE_ADDR is not set\n");
http_code = HTTP_ERROR;
goto fcgi_out;
}
rc = _verify_ip(ip);
if (rc != 0) {
fprintf(stderr, "Incorrect REMOTE_ADDR\n");
http_code = HTTP_BAD_REQUEST;
goto fcgi_out;
}
char *cgi_width = cgiGetValue(cgi, "width");
char *cgi_height = cgiGetValue(cgi, "height");
int bal = 0;
if ( (cgi_width != NULL) && (_verify_geometry(cgi_width) == 0) )
bal++;
if ( (cgi_height != NULL) && (_verify_geometry(cgi_height) == 0) )
bal++;
if (bal == 1) {
error_msg = "Define both width and height";
http_code = HTTP_BAD_REQUEST;
goto fcgi_out;
}
char *hex;
int max_try = 10;
for (int i = 1; i <= max_try; i++) {
if (i == max_try) {
fprintf(stderr, "Error in random file loop\n");
http_code = HTTP_ERROR;
goto fcgi_out;
}
rc = _rand(&hex);
if (rc < 0) {
fprintf(stderr, "Error in _rand()\n");
continue;
}
if (access(hex, F_OK) != 0) {
break;
}
}
FCGI_FILE *d = fopen(hex, "w");
if (d == NULL) {
fprintf(stderr, "Error openning file %s/%s for writing\n", DIR, hex);
http_code = HTTP_ERROR;
goto fcgi_out;
}
fprintf(d, "ip=%s\n", ip);
if (bal == 2) {
fprintf(d, "width=%s\n", cgi_width);
fprintf(d, "height=%s\n", cgi_height);
}
rc = fclose(d);
if (rc != 0) {
fprintf(stderr, "Error closing file %s/%s\n", DIR, hex);
http_code = HTTP_ERROR;
goto fcgi_out;
}
http_code = HTTP_OK;
fcgi_out:
cgiFree(cgi);
printf("Content-Type: text/plain; charset=utf-8\r\n");
printf("Status: %d\r\n", http_code);
printf("\r\n", http_code);
if (http_code == HTTP_OK) {
printf("OK (%s)\r\n", hex);
rc = 0;
} else {
if (error_msg)
printf("ERROR: %s\r\n", error_msg);
rc = 1;
}
}
out:
return rc;
}