|
|
1.1 root 1: /*
2: * QEMU VNC display driver: SASL auth protocol
3: *
4: * Copyright (C) 2009 Red Hat, Inc
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24:
25: #include "vnc.h"
26:
27: /* Max amount of data we send/recv for SASL steps to prevent DOS */
28: #define SASL_DATA_MAX_LEN (1024 * 1024)
29:
30:
31: void vnc_sasl_client_cleanup(VncState *vs)
32: {
33: if (vs->sasl.conn) {
1.1.1.5 ! root 34: vs->sasl.runSSF = false;
! 35: vs->sasl.wantSSF = false;
! 36: vs->sasl.waitWriteSSF = 0;
1.1 root 37: vs->sasl.encodedLength = vs->sasl.encodedOffset = 0;
38: vs->sasl.encoded = NULL;
1.1.1.4 root 39: g_free(vs->sasl.username);
40: g_free(vs->sasl.mechlist);
1.1 root 41: vs->sasl.username = vs->sasl.mechlist = NULL;
42: sasl_dispose(&vs->sasl.conn);
43: vs->sasl.conn = NULL;
44: }
45: }
46:
47:
48: long vnc_client_write_sasl(VncState *vs)
49: {
50: long ret;
51:
52: VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
53: "Encoded: %p size %d offset %d\n",
54: vs->output.buffer, vs->output.capacity, vs->output.offset,
55: vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
56:
57: if (!vs->sasl.encoded) {
58: int err;
59: err = sasl_encode(vs->sasl.conn,
60: (char *)vs->output.buffer,
61: vs->output.offset,
62: (const char **)&vs->sasl.encoded,
63: &vs->sasl.encodedLength);
64: if (err != SASL_OK)
65: return vnc_client_io_error(vs, -1, EIO);
66:
67: vs->sasl.encodedOffset = 0;
68: }
69:
70: ret = vnc_client_write_buf(vs,
71: vs->sasl.encoded + vs->sasl.encodedOffset,
72: vs->sasl.encodedLength - vs->sasl.encodedOffset);
73: if (!ret)
74: return 0;
75:
76: vs->sasl.encodedOffset += ret;
77: if (vs->sasl.encodedOffset == vs->sasl.encodedLength) {
78: vs->output.offset = 0;
79: vs->sasl.encoded = NULL;
80: vs->sasl.encodedOffset = vs->sasl.encodedLength = 0;
81: }
82:
83: /* Can't merge this block with one above, because
84: * someone might have written more unencrypted
85: * data in vs->output while we were processing
86: * SASL encoded output
87: */
88: if (vs->output.offset == 0) {
89: qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
90: }
91:
92: return ret;
93: }
94:
95:
96: long vnc_client_read_sasl(VncState *vs)
97: {
98: long ret;
99: uint8_t encoded[4096];
100: const char *decoded;
101: unsigned int decodedLen;
102: int err;
103:
104: ret = vnc_client_read_buf(vs, encoded, sizeof(encoded));
105: if (!ret)
106: return 0;
107:
108: err = sasl_decode(vs->sasl.conn,
109: (char *)encoded, ret,
110: &decoded, &decodedLen);
111:
112: if (err != SASL_OK)
113: return vnc_client_io_error(vs, -1, -EIO);
114: VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
115: encoded, ret, decoded, decodedLen);
116: buffer_reserve(&vs->input, decodedLen);
117: buffer_append(&vs->input, decoded, decodedLen);
118: return decodedLen;
119: }
120:
121:
122: static int vnc_auth_sasl_check_access(VncState *vs)
123: {
124: const void *val;
125: int err;
126: int allow;
127:
128: err = sasl_getprop(vs->sasl.conn, SASL_USERNAME, &val);
129: if (err != SASL_OK) {
130: VNC_DEBUG("cannot query SASL username on connection %d (%s), denying access\n",
131: err, sasl_errstring(err, NULL, NULL));
132: return -1;
133: }
134: if (val == NULL) {
135: VNC_DEBUG("no client username was found, denying access\n");
136: return -1;
137: }
138: VNC_DEBUG("SASL client username %s\n", (const char *)val);
139:
1.1.1.4 root 140: vs->sasl.username = g_strdup((const char*)val);
1.1 root 141:
142: if (vs->vd->sasl.acl == NULL) {
143: VNC_DEBUG("no ACL activated, allowing access\n");
144: return 0;
145: }
146:
147: allow = qemu_acl_party_is_allowed(vs->vd->sasl.acl, vs->sasl.username);
148:
149: VNC_DEBUG("SASL client %s %s by ACL\n", vs->sasl.username,
150: allow ? "allowed" : "denied");
151: return allow ? 0 : -1;
152: }
153:
154: static int vnc_auth_sasl_check_ssf(VncState *vs)
155: {
156: const void *val;
157: int err, ssf;
158:
159: if (!vs->sasl.wantSSF)
160: return 1;
161:
162: err = sasl_getprop(vs->sasl.conn, SASL_SSF, &val);
163: if (err != SASL_OK)
164: return 0;
165:
166: ssf = *(const int *)val;
167: VNC_DEBUG("negotiated an SSF of %d\n", ssf);
168: if (ssf < 56)
169: return 0; /* 56 is good for Kerberos */
170:
171: /* Only setup for read initially, because we're about to send an RPC
172: * reply which must be in plain text. When the next incoming RPC
173: * arrives, we'll switch on writes too
174: *
175: * cf qemudClientReadSASL in qemud.c
176: */
177: vs->sasl.runSSF = 1;
178:
179: /* We have a SSF that's good enough */
180: return 1;
181: }
182:
183: /*
184: * Step Msg
185: *
186: * Input from client:
187: *
188: * u32 clientin-length
189: * u8-array clientin-string
190: *
191: * Output to client:
192: *
193: * u32 serverout-length
194: * u8-array serverout-strin
195: * u8 continue
196: */
197:
198: static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len);
199:
200: static int protocol_client_auth_sasl_step(VncState *vs, uint8_t *data, size_t len)
201: {
202: uint32_t datalen = len;
203: const char *serverout;
204: unsigned int serveroutlen;
205: int err;
206: char *clientdata = NULL;
207:
208: /* NB, distinction of NULL vs "" is *critical* in SASL */
209: if (datalen) {
210: clientdata = (char*)data;
211: clientdata[datalen-1] = '\0'; /* Wire includes '\0', but make sure */
212: datalen--; /* Don't count NULL byte when passing to _start() */
213: }
214:
215: VNC_DEBUG("Step using SASL Data %p (%d bytes)\n",
216: clientdata, datalen);
217: err = sasl_server_step(vs->sasl.conn,
218: clientdata,
219: datalen,
220: &serverout,
221: &serveroutlen);
222: if (err != SASL_OK &&
223: err != SASL_CONTINUE) {
224: VNC_DEBUG("sasl step failed %d (%s)\n",
225: err, sasl_errdetail(vs->sasl.conn));
226: sasl_dispose(&vs->sasl.conn);
227: vs->sasl.conn = NULL;
228: goto authabort;
229: }
230:
231: if (serveroutlen > SASL_DATA_MAX_LEN) {
232: VNC_DEBUG("sasl step reply data too long %d\n",
233: serveroutlen);
234: sasl_dispose(&vs->sasl.conn);
235: vs->sasl.conn = NULL;
236: goto authabort;
237: }
238:
239: VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
240: serveroutlen, serverout ? 0 : 1);
241:
242: if (serveroutlen) {
243: vnc_write_u32(vs, serveroutlen + 1);
244: vnc_write(vs, serverout, serveroutlen + 1);
245: } else {
246: vnc_write_u32(vs, 0);
247: }
248:
249: /* Whether auth is complete */
250: vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
251:
252: if (err == SASL_CONTINUE) {
253: VNC_DEBUG("%s", "Authentication must continue\n");
254: /* Wait for step length */
255: vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
256: } else {
257: if (!vnc_auth_sasl_check_ssf(vs)) {
258: VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
259: goto authreject;
260: }
261:
262: /* Check username whitelist ACL */
263: if (vnc_auth_sasl_check_access(vs) < 0) {
264: VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
265: goto authreject;
266: }
267:
268: VNC_DEBUG("Authentication successful %d\n", vs->csock);
269: vnc_write_u32(vs, 0); /* Accept auth */
270: /*
271: * Delay writing in SSF encoded mode until pending output
272: * buffer is written
273: */
274: if (vs->sasl.runSSF)
275: vs->sasl.waitWriteSSF = vs->output.offset;
276: start_client_init(vs);
277: }
278:
279: return 0;
280:
281: authreject:
282: vnc_write_u32(vs, 1); /* Reject auth */
283: vnc_write_u32(vs, sizeof("Authentication failed"));
284: vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
285: vnc_flush(vs);
286: vnc_client_error(vs);
287: return -1;
288:
289: authabort:
290: vnc_client_error(vs);
291: return -1;
292: }
293:
294: static int protocol_client_auth_sasl_step_len(VncState *vs, uint8_t *data, size_t len)
295: {
296: uint32_t steplen = read_u32(data, 0);
297: VNC_DEBUG("Got client step len %d\n", steplen);
298: if (steplen > SASL_DATA_MAX_LEN) {
299: VNC_DEBUG("Too much SASL data %d\n", steplen);
300: vnc_client_error(vs);
301: return -1;
302: }
303:
304: if (steplen == 0)
305: return protocol_client_auth_sasl_step(vs, NULL, 0);
306: else
307: vnc_read_when(vs, protocol_client_auth_sasl_step, steplen);
308: return 0;
309: }
310:
311: /*
312: * Start Msg
313: *
314: * Input from client:
315: *
316: * u32 clientin-length
317: * u8-array clientin-string
318: *
319: * Output to client:
320: *
321: * u32 serverout-length
322: * u8-array serverout-strin
323: * u8 continue
324: */
325:
326: #define SASL_DATA_MAX_LEN (1024 * 1024)
327:
328: static int protocol_client_auth_sasl_start(VncState *vs, uint8_t *data, size_t len)
329: {
330: uint32_t datalen = len;
331: const char *serverout;
332: unsigned int serveroutlen;
333: int err;
334: char *clientdata = NULL;
335:
336: /* NB, distinction of NULL vs "" is *critical* in SASL */
337: if (datalen) {
338: clientdata = (char*)data;
339: clientdata[datalen-1] = '\0'; /* Should be on wire, but make sure */
340: datalen--; /* Don't count NULL byte when passing to _start() */
341: }
342:
343: VNC_DEBUG("Start SASL auth with mechanism %s. Data %p (%d bytes)\n",
344: vs->sasl.mechlist, clientdata, datalen);
345: err = sasl_server_start(vs->sasl.conn,
346: vs->sasl.mechlist,
347: clientdata,
348: datalen,
349: &serverout,
350: &serveroutlen);
351: if (err != SASL_OK &&
352: err != SASL_CONTINUE) {
353: VNC_DEBUG("sasl start failed %d (%s)\n",
354: err, sasl_errdetail(vs->sasl.conn));
355: sasl_dispose(&vs->sasl.conn);
356: vs->sasl.conn = NULL;
357: goto authabort;
358: }
359: if (serveroutlen > SASL_DATA_MAX_LEN) {
360: VNC_DEBUG("sasl start reply data too long %d\n",
361: serveroutlen);
362: sasl_dispose(&vs->sasl.conn);
363: vs->sasl.conn = NULL;
364: goto authabort;
365: }
366:
367: VNC_DEBUG("SASL return data %d bytes, nil; %d\n",
368: serveroutlen, serverout ? 0 : 1);
369:
370: if (serveroutlen) {
371: vnc_write_u32(vs, serveroutlen + 1);
372: vnc_write(vs, serverout, serveroutlen + 1);
373: } else {
374: vnc_write_u32(vs, 0);
375: }
376:
377: /* Whether auth is complete */
378: vnc_write_u8(vs, err == SASL_CONTINUE ? 0 : 1);
379:
380: if (err == SASL_CONTINUE) {
381: VNC_DEBUG("%s", "Authentication must continue\n");
382: /* Wait for step length */
383: vnc_read_when(vs, protocol_client_auth_sasl_step_len, 4);
384: } else {
385: if (!vnc_auth_sasl_check_ssf(vs)) {
386: VNC_DEBUG("Authentication rejected for weak SSF %d\n", vs->csock);
387: goto authreject;
388: }
389:
390: /* Check username whitelist ACL */
391: if (vnc_auth_sasl_check_access(vs) < 0) {
392: VNC_DEBUG("Authentication rejected for ACL %d\n", vs->csock);
393: goto authreject;
394: }
395:
396: VNC_DEBUG("Authentication successful %d\n", vs->csock);
397: vnc_write_u32(vs, 0); /* Accept auth */
398: start_client_init(vs);
399: }
400:
401: return 0;
402:
403: authreject:
404: vnc_write_u32(vs, 1); /* Reject auth */
405: vnc_write_u32(vs, sizeof("Authentication failed"));
406: vnc_write(vs, "Authentication failed", sizeof("Authentication failed"));
407: vnc_flush(vs);
408: vnc_client_error(vs);
409: return -1;
410:
411: authabort:
412: vnc_client_error(vs);
413: return -1;
414: }
415:
416: static int protocol_client_auth_sasl_start_len(VncState *vs, uint8_t *data, size_t len)
417: {
418: uint32_t startlen = read_u32(data, 0);
419: VNC_DEBUG("Got client start len %d\n", startlen);
420: if (startlen > SASL_DATA_MAX_LEN) {
421: VNC_DEBUG("Too much SASL data %d\n", startlen);
422: vnc_client_error(vs);
423: return -1;
424: }
425:
426: if (startlen == 0)
427: return protocol_client_auth_sasl_start(vs, NULL, 0);
428:
429: vnc_read_when(vs, protocol_client_auth_sasl_start, startlen);
430: return 0;
431: }
432:
433: static int protocol_client_auth_sasl_mechname(VncState *vs, uint8_t *data, size_t len)
434: {
1.1.1.4 root 435: char *mechname = g_malloc(len + 1);
1.1 root 436: strncpy(mechname, (char*)data, len);
437: mechname[len] = '\0';
438: VNC_DEBUG("Got client mechname '%s' check against '%s'\n",
439: mechname, vs->sasl.mechlist);
440:
441: if (strncmp(vs->sasl.mechlist, mechname, len) == 0) {
442: if (vs->sasl.mechlist[len] != '\0' &&
443: vs->sasl.mechlist[len] != ',') {
444: VNC_DEBUG("One %d", vs->sasl.mechlist[len]);
1.1.1.2 root 445: goto fail;
1.1 root 446: }
447: } else {
448: char *offset = strstr(vs->sasl.mechlist, mechname);
449: VNC_DEBUG("Two %p\n", offset);
450: if (!offset) {
1.1.1.2 root 451: goto fail;
1.1 root 452: }
453: VNC_DEBUG("Two '%s'\n", offset);
454: if (offset[-1] != ',' ||
455: (offset[len] != '\0'&&
456: offset[len] != ',')) {
1.1.1.2 root 457: goto fail;
1.1 root 458: }
459: }
460:
1.1.1.4 root 461: g_free(vs->sasl.mechlist);
1.1 root 462: vs->sasl.mechlist = mechname;
463:
464: VNC_DEBUG("Validated mechname '%s'\n", mechname);
465: vnc_read_when(vs, protocol_client_auth_sasl_start_len, 4);
466: return 0;
1.1.1.2 root 467:
468: fail:
469: vnc_client_error(vs);
1.1.1.4 root 470: g_free(mechname);
1.1.1.2 root 471: return -1;
1.1 root 472: }
473:
474: static int protocol_client_auth_sasl_mechname_len(VncState *vs, uint8_t *data, size_t len)
475: {
476: uint32_t mechlen = read_u32(data, 0);
477: VNC_DEBUG("Got client mechname len %d\n", mechlen);
478: if (mechlen > 100) {
479: VNC_DEBUG("Too long SASL mechname data %d\n", mechlen);
480: vnc_client_error(vs);
481: return -1;
482: }
483: if (mechlen < 1) {
484: VNC_DEBUG("Too short SASL mechname %d\n", mechlen);
485: vnc_client_error(vs);
486: return -1;
487: }
488: vnc_read_when(vs, protocol_client_auth_sasl_mechname,mechlen);
489: return 0;
490: }
491:
492: void start_auth_sasl(VncState *vs)
493: {
494: const char *mechlist = NULL;
495: sasl_security_properties_t secprops;
496: int err;
497: char *localAddr, *remoteAddr;
498: int mechlistlen;
499:
500: VNC_DEBUG("Initialize SASL auth %d\n", vs->csock);
501:
502: /* Get local & remote client addresses in form IPADDR;PORT */
503: if (!(localAddr = vnc_socket_local_addr("%s;%s", vs->csock)))
504: goto authabort;
505:
506: if (!(remoteAddr = vnc_socket_remote_addr("%s;%s", vs->csock))) {
1.1.1.4 root 507: g_free(localAddr);
1.1 root 508: goto authabort;
509: }
510:
511: err = sasl_server_new("vnc",
512: NULL, /* FQDN - just delegates to gethostname */
513: NULL, /* User realm */
514: localAddr,
515: remoteAddr,
516: NULL, /* Callbacks, not needed */
517: SASL_SUCCESS_DATA,
518: &vs->sasl.conn);
1.1.1.4 root 519: g_free(localAddr);
520: g_free(remoteAddr);
1.1 root 521: localAddr = remoteAddr = NULL;
522:
523: if (err != SASL_OK) {
524: VNC_DEBUG("sasl context setup failed %d (%s)",
525: err, sasl_errstring(err, NULL, NULL));
526: vs->sasl.conn = NULL;
527: goto authabort;
528: }
529:
530: #ifdef CONFIG_VNC_TLS
531: /* Inform SASL that we've got an external SSF layer from TLS/x509 */
1.1.1.3 root 532: if (vs->auth == VNC_AUTH_VENCRYPT &&
533: vs->subauth == VNC_AUTH_VENCRYPT_X509SASL) {
1.1 root 534: gnutls_cipher_algorithm_t cipher;
535: sasl_ssf_t ssf;
536:
537: cipher = gnutls_cipher_get(vs->tls.session);
538: if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
539: VNC_DEBUG("%s", "cannot TLS get cipher size\n");
540: sasl_dispose(&vs->sasl.conn);
541: vs->sasl.conn = NULL;
542: goto authabort;
543: }
544: ssf *= 8; /* tls key size is bytes, sasl wants bits */
545:
546: err = sasl_setprop(vs->sasl.conn, SASL_SSF_EXTERNAL, &ssf);
547: if (err != SASL_OK) {
548: VNC_DEBUG("cannot set SASL external SSF %d (%s)\n",
549: err, sasl_errstring(err, NULL, NULL));
550: sasl_dispose(&vs->sasl.conn);
551: vs->sasl.conn = NULL;
552: goto authabort;
553: }
554: } else
555: #endif /* CONFIG_VNC_TLS */
556: vs->sasl.wantSSF = 1;
557:
558: memset (&secprops, 0, sizeof secprops);
559: /* Inform SASL that we've got an external SSF layer from TLS */
560: if (strncmp(vs->vd->display, "unix:", 5) == 0
561: #ifdef CONFIG_VNC_TLS
562: /* Disable SSF, if using TLS+x509+SASL only. TLS without x509
563: is not sufficiently strong */
1.1.1.3 root 564: || (vs->auth == VNC_AUTH_VENCRYPT &&
565: vs->subauth == VNC_AUTH_VENCRYPT_X509SASL)
1.1 root 566: #endif /* CONFIG_VNC_TLS */
567: ) {
568: /* If we've got TLS or UNIX domain sock, we don't care about SSF */
569: secprops.min_ssf = 0;
570: secprops.max_ssf = 0;
571: secprops.maxbufsize = 8192;
572: secprops.security_flags = 0;
573: } else {
574: /* Plain TCP, better get an SSF layer */
575: secprops.min_ssf = 56; /* Good enough to require kerberos */
576: secprops.max_ssf = 100000; /* Arbitrary big number */
577: secprops.maxbufsize = 8192;
578: /* Forbid any anonymous or trivially crackable auth */
579: secprops.security_flags =
580: SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
581: }
582:
583: err = sasl_setprop(vs->sasl.conn, SASL_SEC_PROPS, &secprops);
584: if (err != SASL_OK) {
585: VNC_DEBUG("cannot set SASL security props %d (%s)\n",
586: err, sasl_errstring(err, NULL, NULL));
587: sasl_dispose(&vs->sasl.conn);
588: vs->sasl.conn = NULL;
589: goto authabort;
590: }
591:
592: err = sasl_listmech(vs->sasl.conn,
593: NULL, /* Don't need to set user */
594: "", /* Prefix */
595: ",", /* Separator */
596: "", /* Suffix */
597: &mechlist,
598: NULL,
599: NULL);
600: if (err != SASL_OK) {
601: VNC_DEBUG("cannot list SASL mechanisms %d (%s)\n",
602: err, sasl_errdetail(vs->sasl.conn));
603: sasl_dispose(&vs->sasl.conn);
604: vs->sasl.conn = NULL;
605: goto authabort;
606: }
607: VNC_DEBUG("Available mechanisms for client: '%s'\n", mechlist);
608:
1.1.1.4 root 609: vs->sasl.mechlist = g_strdup(mechlist);
1.1 root 610: mechlistlen = strlen(mechlist);
611: vnc_write_u32(vs, mechlistlen);
612: vnc_write(vs, mechlist, mechlistlen);
613: vnc_flush(vs);
614:
615: VNC_DEBUG("Wait for client mechname length\n");
616: vnc_read_when(vs, protocol_client_auth_sasl_mechname_len, 4);
617:
618: return;
619:
620: authabort:
621: vnc_client_error(vs);
622: return;
623: }
624:
625:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.