1 /*
2  *  This file is called main.c, because it contains most of the new functions
3  *  for use with LibVNCServer.
4  *
5  *  LibVNCServer (C) 2001 Johannes E. Schindelin <Johannes.Schindelin@gmx.de>
6  *  Original OSXvnc (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
7  *  Original Xvnc (C) 1999 AT&T Laboratories Cambridge.
8  *  All Rights Reserved.
9  *
10  *  see GPL (latest version) for full details
11  */
12 
13 #include "rfb/rfb.h"
14 #include "rfb/rfbregion.h"
15 
16 #include <stdarg.h>
17 #include <errno.h>
18 
19 #ifndef false
20 #define false 0
21 #define true -1
22 #endif
23 
24 #ifdef HAVE_SYS_TYPES_H
25 #include <sys/types.h>
26 #endif
27 
28 #ifndef WIN32
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <unistd.h>
32 #endif
33 
34 #include <signal.h>
35 #include <time.h>
36 
37 #include <glib.h>
38 
39 int rfbEnableLogging=1;
40 
41 #ifdef WORDS_BIGENDIAN
42 char rfbEndianTest = 0;
43 #else
44 char rfbEndianTest = -1;
45 #endif
46 
rfbLogEnable(int enabled)47 void rfbLogEnable(int enabled) {
48   rfbEnableLogging=enabled;
49 }
50 
51 /*
52  * rfbLog prints a time-stamped message to the log file (stderr).
53  */
54 
55 static void rfbDefaultLog(const char *format, ...) G_GNUC_PRINTF (1, 2);
56 
57 static void
rfbDefaultLog(const char * format,...)58 rfbDefaultLog(const char *format, ...)
59 {
60     va_list args;
61     char buf[256];
62     time_t log_clock;
63 
64     if(!rfbEnableLogging)
65       return;
66 
67     LOCK(logMutex);
68     va_start(args, format);
69 
70     time(&log_clock);
71     strftime(buf, 255, "%d/%m/%Y %X ", localtime(&log_clock));
72     fprintf(stderr, "%s", buf);
73 
74     vfprintf(stderr, format, args);
75     fflush(stderr);
76 
77     va_end(args);
78     UNLOCK(logMutex);
79 }
80 
81 rfbLogProc rfbLog=rfbDefaultLog;
82 rfbLogProc rfbErr=rfbDefaultLog;
83 
rfbLogPerror(const char * str)84 void rfbLogPerror(const char *str)
85 {
86     rfbErr("%s: %s\n", str, strerror(errno));
87 }
88 
rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)89 void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
90 {
91    rfbClientIteratorPtr iterator;
92    rfbClientPtr cl;
93 
94    iterator=rfbGetClientIterator(rfbScreen);
95    while((cl=rfbClientIteratorNext(iterator))) {
96      LOCK(cl->updateMutex);
97      if(cl->useCopyRect) {
98        sraRegionPtr modifiedRegionBackup;
99        if(!sraRgnEmpty(cl->copyRegion)) {
100 	  if(cl->copyDX!=dx || cl->copyDY!=dy) {
101 	     /* if a copyRegion was not yet executed, treat it as a
102 	      * modifiedRegion. The idea: in this case it could be
103 	      * source of the new copyRect or modified anyway. */
104 	     sraRgnOr(cl->modifiedRegion,cl->copyRegion);
105 	     sraRgnMakeEmpty(cl->copyRegion);
106 	  } else {
107 	     /* we have to set the intersection of the source of the copy
108 	      * and the old copy to modified. */
109 	     modifiedRegionBackup=sraRgnCreateRgn(copyRegion);
110 	     sraRgnOffset(modifiedRegionBackup,-dx,-dy);
111 	     sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
112 	     sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
113 	     sraRgnDestroy(modifiedRegionBackup);
114 	  }
115        }
116 
117        sraRgnOr(cl->copyRegion,copyRegion);
118        cl->copyDX = dx;
119        cl->copyDY = dy;
120 
121        /* if there were modified regions, which are now copied,
122 	* mark them as modified, because the source of these can be overlapped
123 	* either by new modified or now copied regions. */
124        modifiedRegionBackup=sraRgnCreateRgn(cl->modifiedRegion);
125        sraRgnOffset(modifiedRegionBackup,dx,dy);
126        sraRgnAnd(modifiedRegionBackup,cl->copyRegion);
127        sraRgnOr(cl->modifiedRegion,modifiedRegionBackup);
128        sraRgnDestroy(modifiedRegionBackup);
129 
130 #if 0
131        /* TODO: is this needed? Or does it mess up deferring? */
132        /* while(!sraRgnEmpty(cl->copyRegion)) */ {
133 	   {
134 	     sraRegionPtr updateRegion = sraRgnCreateRgn(cl->modifiedRegion);
135 	     sraRgnOr(updateRegion,cl->copyRegion);
136 	     UNLOCK(cl->updateMutex);
137 	     rfbSendFramebufferUpdate(cl,updateRegion);
138 	     sraRgnDestroy(updateRegion);
139 	     continue;
140 	   }
141        }
142 #endif
143      } else {
144        sraRgnOr(cl->modifiedRegion,copyRegion);
145      }
146      UNLOCK(cl->updateMutex);
147    }
148 
149    rfbReleaseClientIterator(iterator);
150 }
151 
rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)152 void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy)
153 {
154    sraRectangleIterator* i;
155    sraRect rect;
156    int j,widthInBytes,bpp=rfbScreen->rfbServerFormat.bitsPerPixel/8,
157     rowstride=rfbScreen->paddedWidthInBytes;
158    char *in,*out;
159 
160    /* copy it, really */
161    i = sraRgnGetReverseIterator(copyRegion,dx<0,dy<0);
162    while(sraRgnIteratorNext(i,&rect)) {
163      widthInBytes = (rect.x2-rect.x1)*bpp;
164      out = rfbScreen->frameBuffer+rect.x1*bpp+rect.y1*rowstride;
165      in = rfbScreen->frameBuffer+(rect.x1-dx)*bpp+(rect.y1-dy)*rowstride;
166      if(dy<0)
167        for(j=rect.y1;j<rect.y2;j++,out+=rowstride,in+=rowstride)
168 	 memmove(out,in,widthInBytes);
169      else {
170        out += rowstride*(rect.y2-rect.y1-1);
171        in += rowstride*(rect.y2-rect.y1-1);
172        for(j=rect.y2-1;j>=rect.y1;j--,out-=rowstride,in-=rowstride)
173 	 memmove(out,in,widthInBytes);
174      }
175    }
176 
177    rfbScheduleCopyRegion(rfbScreen,copyRegion,dx,dy);
178 }
179 
rfbDoCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)180 void rfbDoCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
181 {
182   sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
183   rfbDoCopyRegion(rfbScreen,region,dx,dy);
184 }
185 
rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)186 void rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy)
187 {
188   sraRegionPtr region = sraRgnCreateRect(x1,y1,x2,y2);
189   rfbScheduleCopyRegion(rfbScreen,region,dx,dy);
190 }
191 
rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)192 void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion)
193 {
194    rfbClientIteratorPtr iterator;
195    rfbClientPtr cl;
196 
197    iterator=rfbGetClientIterator(rfbScreen);
198    while((cl=rfbClientIteratorNext(iterator))) {
199      LOCK(cl->updateMutex);
200      sraRgnOr(cl->modifiedRegion,modRegion);
201      UNLOCK(cl->updateMutex);
202    }
203 
204    rfbReleaseClientIterator(iterator);
205 }
206 
rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2)207 void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2)
208 {
209    sraRegionPtr region;
210    int i;
211 
212    if(x1>x2) { i=x1; x1=x2; x2=i; }
213    if(x1<0) x1=0;
214    if(x2>=rfbScreen->width) x2=rfbScreen->width-1;
215    if(x1==x2) return;
216 
217    if(y1>y2) { i=y1; y1=y2; y2=i; }
218    if(y1<0) y1=0;
219    if(y2>=rfbScreen->height) y2=rfbScreen->height-1;
220    if(y1==y2) return;
221 
222    region = sraRgnCreateRect(x1,y1,x2,y2);
223    rfbMarkRegionAsModified(rfbScreen,region);
224    sraRgnDestroy(region);
225 }
226 
227 void
defaultPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl)228 defaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
229 {
230   rfbSetCursorPosition(cl->screen, cl, x, y);
231 }
232 
233 /* TODO: add a nice VNC or RFB cursor */
234 
235 #if defined(WIN32) || defined(sparc) || !defined(NO_STRICT_ANSI)
236 static rfbCursor myCursor =
237 {
238    FALSE, FALSE, FALSE, FALSE,
239    (unsigned char*)"\000\102\044\030\044\102\000",
240    (unsigned char*)"\347\347\176\074\176\347\347",
241    8, 7, 3, 3,
242    0, 0, 0,
243    0xffff, 0xffff, 0xffff,
244    0
245 };
246 #else
247 static rfbCursor myCursor =
248 {
249    cleanup: FALSE,
250    cleanupSource: FALSE,
251    cleanupMask: FALSE,
252    cleanupRichSource: FALSE,
253    source: "\000\102\044\030\044\102\000",
254    mask:   "\347\347\176\074\176\347\347",
255    width: 8, height: 7, xhot: 3, yhot: 3,
256    foreRed: 0, foreGreen: 0, foreBlue: 0,
257    backRed: 0xffff, backGreen: 0xffff, backBlue: 0xffff,
258    richSource: 0
259 };
260 #endif
261 
262 /*
263  * Update server's pixel format in rfbScreenInfo structure. This
264  * function is called from rfbGetScreen() and rfbNewFramebuffer().
265  */
266 
rfbInitServerFormat(rfbScreenInfoPtr rfbScreen,int bitsPerSample)267 static void rfbInitServerFormat(rfbScreenInfoPtr rfbScreen, int bitsPerSample)
268 {
269    rfbPixelFormat* format=&rfbScreen->rfbServerFormat;
270 
271    format->bitsPerPixel = rfbScreen->bitsPerPixel;
272    format->depth = rfbScreen->depth;
273    format->bigEndian = rfbEndianTest?FALSE:TRUE;
274    format->trueColour = TRUE;
275    rfbScreen->colourMap.count = 0;
276    rfbScreen->colourMap.is16 = 0;
277    rfbScreen->colourMap.data.bytes = NULL;
278 
279    if (format->bitsPerPixel == 8) {
280      format->redMax = 7;
281      format->greenMax = 7;
282      format->blueMax = 3;
283      format->redShift = 0;
284      format->greenShift = 3;
285      format->blueShift = 6;
286    } else {
287      format->redMax = (1 << bitsPerSample) - 1;
288      format->greenMax = (1 << bitsPerSample) - 1;
289      format->blueMax = (1 << bitsPerSample) - 1;
290      if(rfbEndianTest) {
291        format->redShift = 0;
292        format->greenShift = bitsPerSample;
293        format->blueShift = bitsPerSample * 2;
294      } else {
295        if(format->bitsPerPixel==8*3) {
296 	 format->redShift = bitsPerSample*2;
297 	 format->greenShift = bitsPerSample*1;
298 	 format->blueShift = 0;
299        } else {
300 	 format->redShift = bitsPerSample*3;
301 	 format->greenShift = bitsPerSample*2;
302 	 format->blueShift = bitsPerSample;
303        }
304      }
305    }
306 }
307 
rfbGetScreen(int * argc,char ** argv,int width,int height,int bitsPerSample,int samplesPerPixel,int bytesPerPixel)308 rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
309  int width,int height,int bitsPerSample,int samplesPerPixel,
310  int bytesPerPixel)
311 {
312    rfbScreenInfoPtr rfbScreen=malloc(sizeof(rfbScreenInfo));
313 
314    if(width&3)
315      rfbErr("WARNING: Width (%d) is not a multiple of 4. VncViewer has problems with that.\n",width);
316 
317    rfbScreen->autoPort=FALSE;
318    rfbScreen->localOnly=FALSE;
319    rfbScreen->rfbClientHead=0;
320    rfbScreen->rfbPort=5900;
321    rfbScreen->socketInitDone=FALSE;
322 
323    rfbScreen->inetdInitDone = FALSE;
324    rfbScreen->inetdSock=-1;
325 
326    rfbScreen->maxFd=0;
327 
328    rfbScreen->rfbListenSock[0] = -1;
329    rfbScreen->rfbListenSockTotal = 0;
330    rfbScreen->netIface = NULL;
331 
332    rfbScreen->desktopName = strdup("LibVNCServer");
333    rfbScreen->rfbAlwaysShared = FALSE;
334    rfbScreen->rfbNeverShared = FALSE;
335    rfbScreen->rfbDontDisconnect = FALSE;
336 
337    rfbScreen->width = width;
338    rfbScreen->height = height;
339    rfbScreen->bitsPerPixel = rfbScreen->depth = 8*bytesPerPixel;
340 
341    rfbScreen->securityTypes[0] = rfbNoAuth;
342    rfbScreen->nSecurityTypes = 0;
343    rfbScreen->authTypes[0] = rfbNoAuth;
344    rfbScreen->nAuthTypes = 0;
345    rfbScreen->passwordCheck = NULL;
346 
347 #ifdef WIN32
348    {
349 	   DWORD dummy=255;
350 	   GetComputerName(rfbScreen->rfbThisHost,&dummy);
351    }
352 #else
353    gethostname(rfbScreen->rfbThisHost, 255);
354 #endif
355 
356    rfbScreen->paddedWidthInBytes = width*bytesPerPixel;
357 
358    /* format */
359 
360    rfbInitServerFormat(rfbScreen, bitsPerSample);
361 
362    /* cursor */
363 
364    rfbScreen->cursorX=rfbScreen->cursorY=rfbScreen->underCursorBufferLen=0;
365    rfbScreen->underCursorBuffer=NULL;
366    rfbScreen->cursor = &myCursor;
367 
368    rfbScreen->rfbDeferUpdateTime=5;
369    rfbScreen->maxRectsPerUpdate=50;
370 
371    /* proc's and hook's */
372 
373    rfbScreen->kbdAddEvent = NULL;
374    rfbScreen->ptrAddEvent = defaultPtrAddEvent;
375    rfbScreen->setXCutText = NULL;
376    rfbScreen->newClientHook = NULL;
377    rfbScreen->authenticatedClientHook = NULL;
378 
379    /* initialize client list and iterator mutex */
380    rfbClientListInit(rfbScreen);
381 
382    rfbAuthInitScreen(rfbScreen);
383 
384    return(rfbScreen);
385 }
386 
387 /*
388  * Switch to another sized framebuffer. Clients supporting NewFBSize
389  * pseudo-encoding will change their local framebuffer dimensions
390  * if necessary.
391  * NOTE: Rich cursor data should be converted to new pixel format by
392  * the caller.
393  */
394 
rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen,char * framebuffer,int width,int height)395 void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer,
396                        int width, int height)
397 {
398   rfbClientIteratorPtr iterator;
399   rfbClientPtr cl;
400 
401   if (width & 3)
402     rfbErr("WARNING: New width (%d) is not a multiple of 4.\n", width);
403 
404   /* Update information in the rfbScreenInfo structure */
405 
406   rfbScreen->width = width;
407   rfbScreen->height = height;
408   rfbScreen->frameBuffer = framebuffer;
409 
410   /* Adjust pointer position if necessary */
411 
412   if (rfbScreen->cursorX >= width)
413     rfbScreen->cursorX = width - 1;
414   if (rfbScreen->cursorY >= height)
415     rfbScreen->cursorY = height - 1;
416 
417   /* For each client: */
418   iterator = rfbGetClientIterator(rfbScreen);
419   while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
420 
421     /* Mark the screen contents as changed, and schedule sending
422        NewFBSize message if supported by this client. */
423 
424     LOCK(cl->updateMutex);
425     sraRgnDestroy(cl->modifiedRegion);
426     cl->modifiedRegion = sraRgnCreateRect(0, 0, width, height);
427     sraRgnMakeEmpty(cl->copyRegion);
428     cl->copyDX = 0;
429     cl->copyDY = 0;
430 
431     if (cl->useNewFBSize)
432       cl->newFBSizePending = TRUE;
433 
434     UNLOCK(cl->updateMutex);
435   }
436   rfbReleaseClientIterator(iterator);
437 }
438 
rfbSetDesktopName(rfbScreenInfoPtr rfbScreen,const char * name)439 void rfbSetDesktopName(rfbScreenInfoPtr rfbScreen, const char *name)
440 {
441   if (rfbScreen->desktopName)
442     free(rfbScreen->desktopName);
443   rfbScreen->desktopName = strdup(name);
444 }
445 
rfbScreenCleanup(rfbScreenInfoPtr rfbScreen)446 void rfbScreenCleanup(rfbScreenInfoPtr rfbScreen)
447 {
448   rfbClientIteratorPtr i=rfbGetClientIterator(rfbScreen);
449   rfbClientPtr cl,cl1=rfbClientIteratorNext(i);
450   while(cl1) {
451     cl=rfbClientIteratorNext(i);
452     rfbClientConnectionGone(cl1);
453     cl1=cl;
454   }
455   rfbReleaseClientIterator(i);
456 
457   rfbAuthCleanupScreen(rfbScreen);
458 
459   /* TODO: hang up on all clients and free all reserved memory */
460 #define FREE_IF(x) if(rfbScreen->x) free(rfbScreen->x)
461   FREE_IF(colourMap.data.bytes);
462   FREE_IF(underCursorBuffer);
463   if(rfbScreen->cursor)
464     rfbFreeCursor(rfbScreen->cursor);
465   if(rfbScreen->desktopName)
466     free(rfbScreen->desktopName);
467   free(rfbScreen);
468 #ifdef VINO_HAVE_JPEG
469   rfbTightCleanup();
470 #endif
471 }
472 
rfbInitServer(rfbScreenInfoPtr rfbScreen)473 void rfbInitServer(rfbScreenInfoPtr rfbScreen)
474 {
475 #ifdef WIN32
476   WSADATA trash;
477   int i=WSAStartup(MAKEWORD(2,2),&trash);
478 #endif
479   rfbInitSockets(rfbScreen);
480 }
481 
482 #ifndef HAVE_GETTIMEOFDAY
483 #include <fcntl.h>
484 #include <conio.h>
485 #include <sys/timeb.h>
486 
gettimeofday(struct timeval * tv,char * dummy)487 void gettimeofday(struct timeval* tv,char* dummy)
488 {
489    SYSTEMTIME t;
490    GetSystemTime(&t);
491    tv->tv_sec=t.wHour*3600+t.wMinute*60+t.wSecond;
492    tv->tv_usec=t.wMilliseconds*1000;
493 }
494 #endif
495 
496 void
rfbUpdateClient(rfbClientPtr cl)497 rfbUpdateClient(rfbClientPtr cl)
498 {
499   struct timeval tv;
500 
501   if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) &&
502       !sraRgnEmpty(cl->requestedRegion)) {
503     if(cl->screen->rfbDeferUpdateTime == 0) {
504       rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
505     } else if(cl->startDeferring.tv_usec == 0) {
506       gettimeofday(&cl->startDeferring,NULL);
507       if(cl->startDeferring.tv_usec == 0)
508 	cl->startDeferring.tv_usec++;
509     } else {
510       gettimeofday(&tv,NULL);
511       if(tv.tv_sec < cl->startDeferring.tv_sec /* at midnight */
512 	 || ((tv.tv_sec-cl->startDeferring.tv_sec)*1000
513 	     +(tv.tv_usec-cl->startDeferring.tv_usec)/1000)
514 	 > cl->screen->rfbDeferUpdateTime) {
515 	cl->startDeferring.tv_usec = 0;
516 	rfbSendFramebufferUpdate(cl,cl->modifiedRegion);
517       }
518     }
519   }
520 }
521 
522 void
rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec)523 rfbProcessEvents(rfbScreenInfoPtr rfbScreen,long usec)
524 {
525   rfbClientIteratorPtr i;
526   rfbClientPtr cl,clPrev;
527 
528   if(usec<0)
529     usec=rfbScreen->rfbDeferUpdateTime*1000;
530 
531   rfbCheckFds(rfbScreen,usec);
532 
533   i = rfbGetClientIterator(rfbScreen);
534   cl=rfbClientIteratorHead(i);
535   while(cl) {
536     rfbUpdateClient(cl);
537     clPrev=cl;
538     cl=rfbClientIteratorNext(i);
539     if(clPrev->sock==-1)
540       rfbClientConnectionGone(clPrev);
541   }
542   rfbReleaseClientIterator(i);
543 }
544 
rfbRunEventLoop(rfbScreenInfoPtr rfbScreen,long usec,rfbBool runInBackground)545 void rfbRunEventLoop(rfbScreenInfoPtr rfbScreen, long usec, rfbBool runInBackground)
546 {
547   if(runInBackground) {
548     rfbErr("Can't run in background, because I don't have PThreads!\n");
549     return;
550   }
551 
552   if(usec<0)
553     usec=rfbScreen->rfbDeferUpdateTime*1000;
554 
555   while(1)
556     rfbProcessEvents(rfbScreen,usec);
557 }
558 
559 static char *
securityTypeToName(int securityType)560 securityTypeToName(int securityType)
561 {
562     switch (securityType) {
563     case rfbNoAuth:
564 	return "No Authentication";
565     case rfbVncAuth:
566 	return "VNC Authentication";
567 #ifdef VINO_HAVE_GNUTLS
568     case rfbTLS:
569 	return "TLS";
570 #endif
571     default:
572 	return "unknown";
573     }
574 }
575 
rfbAddSecurityType(rfbScreenInfoPtr rfbScreen,int securityType)576 void rfbAddSecurityType(rfbScreenInfoPtr rfbScreen, int securityType)
577 {
578     if (rfbScreen->nSecurityTypes >= RFB_MAX_N_SECURITY_TYPES)
579 	return;
580 
581     rfbLog("Advertising security type: '%s' (%d)\n",
582 	   securityTypeToName(securityType), securityType);
583 
584     switch (securityType) {
585     case rfbNoAuth:
586     case rfbVncAuth:
587 #ifdef VINO_HAVE_GNUTLS
588     case rfbTLS:
589 #endif
590 	rfbScreen->securityTypes[rfbScreen->nSecurityTypes] = securityType;
591 	rfbScreen->nSecurityTypes++;
592 	break;
593     default:
594 	break;
595     }
596 }
597 
rfbClearSecurityTypes(rfbScreenInfoPtr rfbScreen)598 void rfbClearSecurityTypes(rfbScreenInfoPtr rfbScreen)
599 {
600     if (rfbScreen->nSecurityTypes > 0) {
601 	rfbLog("Clearing securityTypes\n");
602 
603 	memset (&rfbScreen->securityTypes, 0, sizeof (rfbScreen->securityTypes));
604 	rfbScreen->securityTypes [0] = rfbNoAuth;
605 	rfbScreen->nSecurityTypes = 0;
606     }
607 }
608 
609 static char *
authTypeToName(int authType)610 authTypeToName(int authType)
611 {
612     switch (authType) {
613     case rfbNoAuth:
614 	return "No Authentication";
615     case rfbVncAuth:
616 	return "VNC Authentication";
617     default:
618 	return "unknown";
619     }
620 }
621 
rfbAddAuthType(rfbScreenInfoPtr rfbScreen,int authType)622 void rfbAddAuthType(rfbScreenInfoPtr rfbScreen, int authType)
623 {
624     if (rfbScreen->nAuthTypes >= RFB_MAX_N_AUTH_TYPES)
625 	return;
626 
627     rfbLog("Advertising authentication type: '%s' (%d)\n",
628 	   authTypeToName(authType), authType);
629 
630     switch (authType) {
631     case rfbNoAuth:
632     case rfbVncAuth:
633 	rfbScreen->authTypes[rfbScreen->nAuthTypes] = authType;
634 	rfbScreen->nAuthTypes++;
635 	break;
636     default:
637 	break;
638     }
639 }
640 
rfbClearAuthTypes(rfbScreenInfoPtr rfbScreen)641 void rfbClearAuthTypes(rfbScreenInfoPtr rfbScreen)
642 {
643     if (rfbScreen->nAuthTypes > 0) {
644 	rfbLog("Clearing authTypes\n");
645 
646 	memset (&rfbScreen->authTypes, 0, sizeof (rfbScreen->authTypes));
647 	rfbScreen->authTypes [0] = rfbNoAuth;
648 	rfbScreen->nAuthTypes = 0;
649     }
650 }
651