#include <sys/time.h>
#include <signal.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
#include <glib.h>
} \
}
+static char *auth_path = "/";
+static char *auth_perm = "Sys.Console";
+static char clientip[INET6_ADDRSTRLEN];
+
static GMainLoop *main_loop;
static SpiceCoreInterface core;
sigaction(SIGPIPE, &act, NULL);
}
+static char *
+urlencode(char *buf, const char *value)
+{
+ static const char *hexchar = "0123456789abcdef";
+ char *p = buf;
+ int i;
+ int l = strlen(value);
+ for (i = 0; i < l; i++) {
+ char c = value[i];
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9')) {
+ *p++ = c;
+ } else if (c == 32) {
+ *p++ = '+';
+ } else {
+ *p++ = '%';
+ *p++ = hexchar[c >> 4];
+ *p++ = hexchar[c & 15];
+ }
+ }
+ *p = 0;
+
+ return p;
+}
+
+static int
+pve_auth_verify(const char *clientip, const char *username, const char *passwd)
+{
+ struct sockaddr_in server;
+
+ int sfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sfd == -1) {
+ perror("pve_auth_verify: socket failed");
+ return -1;
+ }
+
+ struct hostent *he;
+ if ((he = gethostbyname("localhost")) == NULL) {
+ fprintf(stderr, "pve_auth_verify: error resolving hostname\n");
+ goto err;
+ }
+
+ memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
+ server.sin_family = AF_INET;
+ server.sin_port = htons(85);
+
+ if (connect(sfd, (struct sockaddr *)&server, sizeof(server))) {
+ perror("pve_auth_verify: error connecting to server");
+ goto err;
+ }
+
+ char buf[8192];
+ char form[8192];
+
+ char *p = form;
+ p = urlencode(p, "username");
+ *p++ = '=';
+ p = urlencode(p, username);
+
+ *p++ = '&';
+ p = urlencode(p, "password");
+ *p++ = '=';
+ p = urlencode(p, passwd);
+
+ *p++ = '&';
+ p = urlencode(p, "path");
+ *p++ = '=';
+ p = urlencode(p, auth_path);
+
+ *p++ = '&';
+ p = urlencode(p, "privs");
+ *p++ = '=';
+ p = urlencode(p, auth_perm);
+
+ sprintf(buf, "POST /api2/json/access/ticket HTTP/1.1\n"
+ "Host: localhost:85\n"
+ "Connection: close\n"
+ "PVEClientIP: %s\n"
+ "Content-Type: application/x-www-form-urlencoded\n"
+ "Content-Length: %zd\n\n%s\n", clientip, strlen(form), form);
+ ssize_t len = strlen(buf);
+ ssize_t sb = send(sfd, buf, len, 0);
+ if (sb < 0) {
+ perror("pve_auth_verify: send failed");
+ goto err;
+ }
+ if (sb != len) {
+ fprintf(stderr, "pve_auth_verify: partial send error\n");
+ goto err;
+ }
+
+ len = recv(sfd, buf, sizeof(buf) - 1, 0);
+ if (len < 0) {
+ perror("pve_auth_verify: recv failed");
+ goto err;
+ }
+
+ buf[len] = 0;
+
+ //printf("DATA:%s\n", buf);
+
+ shutdown(sfd, SHUT_RDWR);
+
+ if (!strncmp(buf, "HTTP/1.1 200 OK", 15)) {
+ return 0;
+ }
+
+ char *firstline = strtok(buf, "\n");
+
+ fprintf(stderr, "auth failed: %s\n", firstline);
+
+ return -1;
+
+err:
+ shutdown(sfd, SHUT_RDWR);
+ return -1;
+}
+
+static int
+verify_credentials(const char *username, const char *password)
+{
+ return pve_auth_verify(clientip, username, password);
+}
+
SpiceCoreInterface *basic_event_loop_init(void)
{
main_loop = g_main_loop_new(NULL, FALSE);
core.watch_remove = watch_remove;
core.channel_event = channel_event;
+ core.auth_plain_verify_credentials = verify_credentials;
+
ignore_sigpipe();
return &core;