VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/lightdm-greeter/vbox-greeter.cpp@ 45356

Last change on this file since 45356 was 45170, checked in by vboxsync, 12 years ago

Additions/linux: lightdm-greeter to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.5 KB
Line 
1/* $Id: vbox-greeter.cpp 45170 2013-03-25 13:35:53Z vboxsync $ */
2/** @file
3 * vbox-greeter - an own LightDM greeter module supporting auto-logons
4 * controlled by the host.
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <pwd.h>
23#include <syslog.h>
24#include <stdlib.h>
25
26#include <lightdm.h>
27#ifdef VBOX_WITH_FLTK
28# include <FL/Fl.H>
29# include <FL/fl_ask.H> /* Yes, the casing is correct for 1.3.0 -- d'oh. */
30# include <FL/Fl_Box.H>
31# include <FL/Fl_Button.H>
32# include <FL/fl_draw.H> /* Same as above. */
33# include <FL/Fl_Double_Window.H>
34# include <FL/Fl_Input.H>
35# include <FL/Fl_Menu_Button.H>
36# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
37# include <FL/Fl_PNG_Image.H>
38# include <FL/Fl_Shared_Image.H>
39# endif
40# include <FL/Fl_Secret_Input.H>
41#else
42# include <cairo-xlib.h>
43# include <gtk/gtk.h>
44# include <gdk/gdkx.h>
45#endif
46
47#include <package-generated.h>
48#include "product-generated.h"
49
50#include <iprt/assert.h>
51#include <iprt/buildconfig.h>
52#include <iprt/env.h>
53#include <iprt/file.h>
54#include <iprt/getopt.h>
55#include <iprt/initterm.h>
56#include <iprt/mem.h>
57#include <iprt/message.h>
58#include <iprt/path.h>
59#include <iprt/process.h>
60#include <iprt/stream.h>
61#include <iprt/system.h>
62#include <iprt/string.h>
63#include <iprt/time.h>
64
65#include <VBox/log.h>
66#include <VBox/VBoxGuestLib.h>
67
68/* The greeter's full name for logging. */
69#define VBOX_MODULE_NAME "vbox-lightdm-greeter"
70
71/* UI elements used in this greeter. */
72#define VBOX_GREETER_UI_WND_GREETER "wnd_greeter"
73
74#define VBOX_GREETER_UI_EDT_USER "edt_username"
75#define VBOX_GREETER_UI_EDT_PASSWORD "edt_password"
76#define VBOX_GREETER_UI_BTN_LOGIN "btn_login"
77#define VBOX_GREETER_UI_LBL_INFO "lbl_info"
78
79/* UI display options. */
80/** Show the restart menu entry / button. */
81#define VBOX_GREETER_UI_SHOW_RESTART RT_BIT(0)
82/** Show the shutdown menu entry / button. */
83#define VBOX_GREETER_UI_SHOW_SHUTDOWN RT_BIT(1)
84/** Show the (customized) top banner. */
85#define VBOX_GREETER_UI_SHOW_BANNER RT_BIT(2)
86/** Enable custom colors */
87#define VBOX_GREETER_UI_USE_THEMING RT_BIT(3)
88
89/** Extracts the 8-bit red component from an uint32_t. */
90#define VBOX_RGB_COLOR_RED(uColor) uColor & 0xFF
91/** Extracts the 8-bit green component from an uint32_t. */
92#define VBOX_RGB_COLOR_GREEN(uColor) (uColor >> 8) & 0xFF
93/** Extracts the 8-bit blue component from an uint32_t. */
94#define VBOX_RGB_COLOR_BLUE(uColor) (uColor >> 16) & 0xFF
95
96#include <VBox/log.h>
97#ifdef VBOX_WITH_GUEST_PROPS
98 #include <VBox/HostServices/GuestPropertySvc.h>
99 using namespace guestProp;
100#endif
101
102/** The program name (derived from argv[0]). */
103char *g_pszProgName = (char *)"";
104/** For debugging. */
105#ifdef DEBUG
106 static int g_iVerbosity = 99;
107#else
108 static int g_iVerbosity = 0;
109#endif
110
111/** Logging parameters. */
112/** @todo Make this configurable later. */
113static PRTLOGGER g_pLoggerRelease = NULL;
114static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
115static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
116static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
117
118/**
119 * Context structure which contains all needed
120 * data within callbacks.
121 */
122typedef struct VBOXGREETERCTX
123{
124 /** Pointer to this greeter instance. */
125 LightDMGreeter *pGreeter;
126#ifdef VBOX_WITH_FLTK
127 Fl_Button *pBtnLogin;
128 Fl_Input *pEdtUsername;
129 Fl_Secret_Input *pEdtPassword;
130 Fl_Box *pLblInfo;
131#else
132 /** The GTK builder instance for accessing
133 * the UI elements. */
134 GtkBuilder *pBuilder;
135#endif
136 /** The timeout (in ms) to wait for credentials. */
137 uint32_t uTimeoutMS;
138 /** The starting timestamp (in ms) to calculate
139 * the timeout. */
140 uint64_t uStartMS;
141 /** Timestamp of last abort message. */
142 uint64_t uTsAbort;
143 /** The HGCM client ID. */
144 uint32_t uClientId;
145 /** The credentials. */
146 char *pszUsername;
147 char *pszPassword;
148 char *pszDomain;
149} VBOXGREETERCTX, *PVBOXGREETERCTX;
150
151static void vboxGreeterError(const char *pszFormat, ...)
152{
153 va_list va;
154 char *buf;
155 va_start(va, pszFormat);
156 if (RTStrAPrintfV(&buf, pszFormat, va))
157 {
158 RTLogRelPrintf("%s: error: %s", VBOX_MODULE_NAME, buf);
159 RTStrFree(buf);
160 }
161 va_end(va);
162}
163
164static void vboxGreeterLog(const char *pszFormat, ...)
165{
166 if (g_iVerbosity)
167 {
168 va_list va;
169 char *buf;
170 va_start(va, pszFormat);
171 if (RTStrAPrintfV(&buf, pszFormat, va))
172 {
173 /* Only do normal logging in debug mode; could contain
174 * sensitive data! */
175 RTLogRelPrintf("%s: %s", VBOX_MODULE_NAME, buf);
176 RTStrFree(buf);
177 }
178 va_end(va);
179 }
180}
181
182/** @tood Move the following two functions to VbglR3 (also see pam_vbox). */
183#ifdef VBOX_WITH_GUEST_PROPS
184/**
185 * Reads a guest property.
186 *
187 * @return IPRT status code.
188 * @param hPAM PAM handle.
189 * @param uClientID Guest property service client ID.
190 * @param pszKey Key (name) of guest property to read.
191 * @param fReadOnly Indicates whether this key needs to be
192 * checked if it only can be read (and *not* written)
193 * by the guest.
194 * @param pszValue Buffer where to store the key's value.
195 * @param cbValue Size of buffer (in bytes).
196 * @param puTimestamp Timestamp of the value
197 * retrieved. Optional.
198 */
199static int vbox_read_prop(uint32_t uClientID,
200 const char *pszKey, bool fReadOnly,
201 char *pszValue, size_t cbValue, uint64_t *puTimestamp)
202{
203 AssertReturn(uClientID, VERR_INVALID_PARAMETER);
204 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
205 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
206 /* puTimestamp is optional. */
207
208 int rc;
209
210 uint64_t u64Timestamp = 0;
211 char *pszValTemp;
212 char *pszFlags = NULL;
213 /* The buffer for storing the data and its initial size. We leave a bit
214 * of space here in case the maximum values are raised. */
215 void *pvBuf = NULL;
216 uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
217
218 /* Because there is a race condition between our reading the size of a
219 * property and the guest updating it, we loop a few times here and
220 * hope. Actually this should never go wrong, as we are generous
221 * enough with buffer space. */
222 for (unsigned i = 0; i < 10; i++)
223 {
224 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
225 if (pvTmpBuf)
226 {
227 pvBuf = pvTmpBuf;
228 rc = VbglR3GuestPropRead(uClientID, pszKey, pvBuf, cbBuf,
229 &pszValTemp, &u64Timestamp, &pszFlags,
230 &cbBuf);
231 }
232 else
233 rc = VERR_NO_MEMORY;
234
235 switch (rc)
236 {
237 case VERR_BUFFER_OVERFLOW:
238 {
239 /* Buffer too small, try it with a bigger one next time. */
240 cbBuf += _1K;
241 continue; /* Try next round. */
242 }
243
244 default:
245 break;
246 }
247
248 /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
249 break;
250 }
251
252 if (RT_SUCCESS(rc))
253 {
254 /* Check security bits. */
255 if (pszFlags)
256 {
257 if (fReadOnly
258 && !RTStrStr(pszFlags, "RDONLYGUEST"))
259 {
260 /* If we want a property which is read-only on the guest
261 * and it is *not* marked as such, deny access! */
262 rc = VERR_ACCESS_DENIED;
263 }
264 }
265 else /* No flags, no access! */
266 rc = VERR_ACCESS_DENIED;
267
268 if (RT_SUCCESS(rc))
269 {
270 /* If everything went well copy property value to our destination buffer. */
271 if (!RTStrPrintf(pszValue, cbValue, "%s", pszValTemp))
272 rc = VERR_BUFFER_OVERFLOW;
273
274 if (puTimestamp)
275 *puTimestamp = u64Timestamp;
276 }
277 }
278
279 return rc;
280}
281
282/**
283 * Waits for a guest property to be changed.
284 *
285 * @return IPRT status code.
286 * @param hPAM PAM handle.
287 * @param uClientID Guest property service client ID.
288 * @param pszKey Key (name) of guest property to wait for.
289 * @param uTimeoutMS Timeout (in ms) to wait for the change. Specify
290 * RT_INDEFINITE_WAIT to wait indefinitly.
291 */
292static int vbox_wait_prop(uint32_t uClientID,
293 const char *pszKey, uint32_t uTimeoutMS)
294{
295 AssertReturn(uClientID, VERR_INVALID_PARAMETER);
296 AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
297
298 int rc;
299
300 /* The buffer for storing the data and its initial size. We leave a bit
301 * of space here in case the maximum values are raised. */
302 void *pvBuf = NULL;
303 uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + _1K;
304
305 for (int i = 0; i < 10; i++)
306 {
307 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
308 if (pvTmpBuf)
309 {
310 char *pszName = NULL;
311 char *pszValue = NULL;
312 uint64_t u64TimestampOut = 0;
313 char *pszFlags = NULL;
314
315 pvBuf = pvTmpBuf;
316 rc = VbglR3GuestPropWait(uClientID, pszKey, pvBuf, cbBuf,
317 0 /* Last timestamp; just wait for next event */, uTimeoutMS,
318 &pszName, &pszValue, &u64TimestampOut,
319 &pszFlags, &cbBuf);
320 }
321 else
322 rc = VERR_NO_MEMORY;
323
324 if (rc == VERR_BUFFER_OVERFLOW)
325 {
326 /* Buffer too small, try it with a bigger one next time. */
327 cbBuf += _1K;
328 continue; /* Try next round. */
329 }
330
331 /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
332 break;
333 }
334
335 return rc;
336}
337#endif /* VBOX_WITH_GUEST_PROPS */
338
339/**
340 * Checks for credentials provided by the host / HGCM.
341 *
342 * @return IPRT status code. VERR_NOT_FOUND if no credentials are available,
343 * VINF_SUCCESS on successful retrieval or another IPRT error.
344 * @param pCtx Greeter context.
345 */
346static int vboxGreeterCheckCreds(PVBOXGREETERCTX pCtx)
347{
348 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
349
350 int rc = VbglR3CredentialsQueryAvailability();
351 if (RT_FAILURE(rc))
352 {
353 if (rc != VERR_NOT_FOUND)
354 vboxGreeterError("vboxGreeterCheckCreds: could not query for credentials! rc=%Rrc. Aborting\n", rc);
355#ifdef DEBUG
356 else
357 vboxGreeterLog("vboxGreeterCheckCreds: no credentials available\n");
358#endif
359 }
360 else
361 {
362 rc = VbglR3CredentialsRetrieve(&pCtx->pszUsername, &pCtx->pszPassword, &pCtx->pszDomain);
363 if (RT_FAILURE(rc))
364 {
365 vboxGreeterError("vboxGreeterCheckCreds: could not retrieve credentials! rc=%Rrc. Aborting\n", rc);
366 }
367 else
368 {
369#ifdef DEBUG
370 vboxGreeterLog("vboxGreeterCheckCreds: credentials retrieved: user=%s, password=%s, domain=%s\n",
371 pCtx->pszUsername, pCtx->pszPassword, pCtx->pszDomain);
372#else
373 /* Don't log passwords in release mode! */
374 vboxGreeterLog("vboxGreeterCheckCreds: credentials retrieved: user=%s, password=XXX, domain=%s\n",
375 pCtx->pszUsername, pCtx->pszDomain);
376#endif
377 lightdm_greeter_authenticate(pCtx->pGreeter, pCtx->pszUsername); /* Must be the real user name from host! */
378 /** @todo Add handling domains as well. */
379 /** @todo Move into context destroy! */
380#if 0
381 VbglR3CredentialsDestroy(pszUsername, pszPassword, pszDomain,
382 3 /* Three wipe passes */);
383#endif
384 }
385 }
386
387#ifdef DEBUG
388 vboxGreeterLog("vboxGreeterCheckCreds: returned with rc=%Rrc\n", rc);
389#endif
390 return rc;
391}
392
393/**
394 * Called by LightDM when greeter is not needed anymore.
395 *
396 * @param signum Signal number.
397 */
398static void cb_sigterm(int signum)
399{
400 vboxGreeterLog("received SIGTERM (%d), exiting\n", signum);
401
402 exit(RTEXITCODE_SUCCESS);
403}
404
405/**
406 * Callback for showing a user prompt, issued by the LightDM server.
407 *
408 * @param pGreeter Pointer to this greeter instance.
409 * @param pszText Text to display.
410 * @param enmType Type of prompt to display.
411 * @param pvData Pointer to user-supplied data.
412 */
413static void cb_lightdm_show_prompt(LightDMGreeter *pGreeter,
414 const gchar *pszText, LightDMPromptType enmType,
415 gpointer pvData)
416{
417 vboxGreeterLog("cb_lightdm_show_prompt: %s (%d)\n", pszText, enmType);
418
419 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
420 AssertPtr(pCtx);
421
422 switch (enmType)
423 {
424 case 1: /* Password. */
425 {
426 if (pCtx->pszPassword)
427 {
428 lightdm_greeter_respond(pGreeter, pCtx->pszPassword);
429 }
430 else
431 {
432#ifdef VBOX_WITH_FLTK
433 AssertPtr(pCtx->pEdtPassword);
434 const char *pszPwd = pCtx->pEdtPassword->value();
435#else
436 GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, "edt_password"));
437 AssertPtr(pEdtPwd);
438 const gchar *pszPwd = gtk_entry_get_text(pEdtPwd);
439#endif
440 lightdm_greeter_respond(pGreeter, pszPwd);
441 }
442 break;
443 }
444
445 default:
446 break;
447 }
448
449 VbglR3CredentialsDestroy(pCtx->pszUsername, pCtx->pszPassword, pCtx->pszDomain,
450 3 /* Three wipe passes */);
451}
452
453/**
454 * Callback for showing a message, issued by the LightDM server.
455 *
456 * @param pGreeter Pointer to this greeter instance.
457 * @param pszText Text to display.
458 * @param enmType Type of message to display.
459 * @param pvData Pointer to user-supplied data.
460 */
461static void cb_lightdm_show_message(LightDMGreeter *pGreeter,
462 const gchar *pszText, LightDMPromptType enmType,
463 gpointer pvData)
464{
465 vboxGreeterLog("cb_lightdm_show_message: %s (%d)\n", pszText, enmType);
466
467 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
468 AssertPtr(pCtx);
469
470#ifdef VBOX_WITH_FLTK
471 AssertPtr(pCtx->pLblInfo);
472 pCtx->pLblInfo->label(pszText);
473#else
474 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, "lbl_info"));
475 AssertPtr(pLblInfo);
476 gtk_label_set_text(pLblInfo, pszText);
477#endif
478}
479
480/**
481 * Callback for authentication completion, issued by the LightDM server.
482 *
483 * @param pGreeter Pointer to this greeter instance.
484 */
485static void cb_lightdm_auth_complete(LightDMGreeter *pGreeter)
486{
487 vboxGreeterLog("cb_lightdm_auth_complete\n");
488
489 const gchar *pszUser = lightdm_greeter_get_authentication_user(pGreeter);
490 vboxGreeterLog("authenticating user: %s\n", pszUser ? pszUser : "<NULL>");
491
492 if (lightdm_greeter_get_is_authenticated(pGreeter))
493 {
494 lightdm_greeter_start_session_sync(pGreeter, NULL, NULL);
495
496 gchar *pszSession = g_strdup(lightdm_greeter_get_default_session_hint(pGreeter));
497 if (pszSession)
498 {
499 vboxGreeterLog("starting session: %s\n", pszSession);
500 if (!lightdm_greeter_start_session_sync(pGreeter, pszSession, NULL))
501 {
502 vboxGreeterError("unable to start session '%s'\n", pszSession);
503 }
504 g_free(pszSession);
505 }
506 else
507 vboxGreeterError("unable to get default session\n");
508 }
509 else
510 vboxGreeterLog("user not authenticated successfully (yet)\n");
511}
512
513/**
514 * Callback for clicking on the "Login" button.
515 *
516 * @param pWidget Widget this callback is bound to.
517 * @param pvData Pointer to user-supplied data.
518 */
519#ifdef VBOX_WITH_FLTK
520void cb_btn_login(Fl_Widget *pWidget, void *pvData)
521#else
522void cb_btn_login(GtkWidget *pWidget, gpointer pvData)
523#endif
524{
525 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
526 AssertPtr(pCtx);
527
528#ifdef VBOX_WITH_FLTK
529 AssertPtr(pCtx->pEdtUsername);
530 const char *pszUser = pCtx->pEdtUsername->value();
531 AssertPtr(pCtx->pEdtPassword);
532 const char *pszPwd = pCtx->pEdtPassword->value();
533#else
534 GtkEntry *pEdtUser = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_USER));
535 AssertPtr(pEdtUser);
536 const gchar *pszUser = gtk_entry_get_text(pEdtUser);
537
538 GtkEntry *pEdtPwd = GTK_ENTRY(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_EDT_PASSWORD));
539 AssertPtr(pEdtPwd);
540 const gchar *pszPwd = gtk_entry_get_text(pEdtPwd);
541#endif
542
543 /** @todo Add domain handling? */
544#ifdef DEBUG
545 vboxGreeterLog("login requested: greeter=%p, user=%s, password=%s\n",
546 pCtx->pGreeter,
547 pszUser ? pszUser : "<NONE>",
548 pszPwd ? pszPwd : "<NONE>");
549#endif
550
551 lightdm_greeter_respond(pCtx->pGreeter, pszPwd);
552 lightdm_greeter_authenticate(pCtx->pGreeter, pszUser);
553}
554
555/**
556 * Callback for clicking on the "Menu" button.
557 *
558 * @param pWidget Widget this callback is bound to.
559 * @param pvData Pointer to user-supplied data.
560 */
561#ifdef VBOX_WITH_FLTK
562void cb_btn_menu(Fl_Widget *pWidget, void *pvData)
563#else
564void cb_btn_menu(GtkWidget *pWidget, gpointer pvData)
565#endif
566{
567
568}
569
570/**
571 * Callback for clicking on the "Restart" button / menu entry.
572 *
573 * @param pWidget Widget this callback is bound to.
574 * @param pvData Pointer to user-supplied data.
575 */
576#ifdef VBOX_WITH_FLTK
577void cb_btn_restart(Fl_Widget *pWidget, void *pvData)
578#else
579void cb_btn_restart(GtkWidget *pWidget, gpointer pvData)
580#endif
581{
582 bool fRestart = true;
583#ifdef VBOX_WITH_FLTK
584 int rc = fl_choice("Really restart the system?", "Yes", "No", NULL);
585 fRestart = rc == 0;
586#endif
587
588 if (fRestart)
589 {
590 vboxGreeterLog("restart requested\n");
591#ifndef DEBUG
592 lightdm_restart(NULL);
593#endif
594 }
595}
596
597/**
598 * Callback for clicking on the "Shutdown" button / menu entry.
599 *
600 * @param pWidget Widget this callback is bound to.
601 * @param pvData Pointer to user-supplied data.
602 */
603#ifdef VBOX_WITH_FLTK
604void cb_btn_shutdown(Fl_Widget *pWidget, void *pvData)
605#else
606void cb_btn_shutdown(GtkWidget *pWidget, gpointer pvData)
607#endif
608{
609 bool fShutdown = true;
610#ifdef VBOX_WITH_FLTK
611 int rc = fl_choice("Really shutdown the system?", "Yes", "No", NULL);
612 fShutdown = rc == 0;
613#endif
614
615 if (fShutdown)
616 {
617 vboxGreeterLog("shutdown requested\n");
618#ifndef DEBUG
619 lightdm_shutdown(NULL);
620#endif
621 }
622}
623
624#ifdef VBOX_WITH_FLTK
625void cb_edt_username(Fl_Widget *pWidget, void *pvData)
626#else
627void cb_edt_username(GtkWidget *pWidget, gpointer pvData)
628#endif
629{
630 vboxGreeterLog("cb_edt_username called\n");
631
632 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
633 AssertPtr(pCtx);
634#ifdef VBOX_WITH_FLTK
635 AssertPtr(pCtx->pEdtPassword);
636 Fl::focus(pCtx->pEdtPassword);
637#endif
638}
639
640#ifdef VBOX_WITH_FLTK
641void cb_edt_password(Fl_Widget *pWidget, void *pvData)
642#else
643void cb_edt_password(GtkWidget *pWidget, gpointer pvData)
644#endif
645{
646 vboxGreeterLog("cb_edt_password called\n");
647
648 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
649 AssertPtr(pCtx);
650#ifdef VBOX_WITH_FLTK
651 AssertPtr(pCtx->pBtnLogin);
652 cb_btn_login(pCtx->pBtnLogin, pvData);
653#endif
654}
655
656/**
657 * Callback for the timer event which is checking for new credentials
658 * from the host.
659 *
660 * @param pvData Pointer to user-supplied data.
661 */
662#ifdef VBOX_WITH_FLTK
663static void cb_check_creds(void *pvData)
664#else
665static gboolean cb_check_creds(gpointer pvData)
666#endif
667{
668 PVBOXGREETERCTX pCtx = (PVBOXGREETERCTX)pvData;
669 AssertPtr(pCtx);
670
671#ifdef DEBUG
672 vboxGreeterLog("cb_check_creds called, clientId=%RU32, timeoutMS=%RU32\n",
673 pCtx->uClientId, pCtx->uTimeoutMS);
674#endif
675
676 int rc = VINF_SUCCESS;
677
678#ifdef VBOX_WITH_GUEST_PROPS
679 bool fAbort = false;
680 char szVal[255];
681 if (pCtx->uClientId)
682 {
683 uint64_t tsAbort;
684 rc = vbox_read_prop(pCtx->uClientId,
685 "/VirtualBox/GuestAdd/PAM/CredsWaitAbort",
686 true /* Read-only on guest */,
687 szVal, sizeof(szVal), &tsAbort);
688 switch (rc)
689 {
690 case VINF_SUCCESS:
691#ifdef DEBUG
692 vboxGreeterLog("cb_check_creds: tsAbort %RU64 <-> %RU64\n",
693 pCtx->uTsAbort, tsAbort);
694#endif
695 if (tsAbort != pCtx->uTsAbort)
696 fAbort = true; /* Timestamps differs, abort. */
697 pCtx->uTsAbort = tsAbort;
698 break;
699
700 case VERR_TOO_MUCH_DATA:
701 vboxGreeterError("cb_check_creds: temporarily unable to get abort notification\n");
702 break;
703
704 case VERR_NOT_FOUND:
705 /* Value not found, continue checking for credentials. */
706 break;
707
708 default:
709 vboxGreeterError("cb_check_creds: the abort notification request failed with rc=%Rrc\n", rc);
710 fAbort = true; /* Abort on error. */
711 break;
712 }
713 }
714
715 if (fAbort)
716 {
717 /* Get optional message. */
718 int rc2 = vbox_read_prop(pCtx->uClientId,
719 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort",
720 true /* Read-only on guest */,
721 szVal, sizeof(szVal), NULL /* Timestamp. */);
722 if (RT_SUCCESS(rc2))
723 {
724# ifdef VBOX_WITH_FLTK
725 /** @todo */
726# else
727 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO));
728 AssertPtr(pLblInfo);
729 gtk_label_set_text(pLblInfo, szVal);
730# endif /* VBOX_WITH_FLTK */
731 }
732
733 vboxGreeterLog("cb_check_creds: got notification from host to abort waiting\n");
734 }
735 else
736 {
737#endif /* VBOX_WITH_GUEST_PROPS */
738 rc = vboxGreeterCheckCreds(pCtx);
739 if (RT_SUCCESS(rc))
740 {
741 /* Credentials retrieved. */
742 }
743 else if (rc == VERR_NOT_FOUND)
744 {
745 /* No credentials found, but try next round (if there's
746 * time left for) ... */
747 }
748#ifdef VBOX_WITH_GUEST_PROPS
749 }
750#endif /* VBOX_WITH_GUEST_PROPS */
751
752 if (rc == VERR_NOT_FOUND) /* No credential found this round. */
753 {
754 /* Calculate timeout value left after process has been started. */
755 uint64_t u64Elapsed = RTTimeMilliTS() - pCtx->uStartMS;
756 /* Is it time to bail out? */
757 if (pCtx->uTimeoutMS < u64Elapsed)
758 {
759#ifdef VBOX_WITH_GUEST_PROPS
760 int rc2 = vbox_read_prop(pCtx->uClientId,
761 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout",
762 true /* Read-only on guest */,
763 szVal, sizeof(szVal), NULL /* Timestamp. */);
764 if (RT_SUCCESS(rc2))
765 {
766# ifdef VBOX_WITH_FLTK
767 /** @todo */
768# else
769 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pCtx->pBuilder, VBOX_GREETER_UI_LBL_INFO));
770 AssertPtr(pLblInfo);
771 gtk_label_set_text(pLblInfo, szVal);
772# endif
773 }
774#endif /* VBOX_WITH_GUEST_PROPS */
775 vboxGreeterLog("cb_check_creds: waiting thread has reached timeout (%dms), exiting ...\n",
776 pCtx->uTimeoutMS);
777 rc = VERR_TIMEOUT;
778 }
779 }
780
781#ifdef DEBUG
782 vboxGreeterLog("cb_check_creds returned with rc=%Rrc\n", rc);
783#endif
784
785 /* At the moment we only allow *one* shot from the host,
786 * so setting credentials in a second attempt won't be possible
787 * intentionally. */
788
789 if (rc == VERR_NOT_FOUND)
790#ifdef VBOX_WITH_FLTK
791 Fl::repeat_timeout(0.5 /* 500 ms */, cb_check_creds, pvData);
792#else
793 return TRUE; /* No credentials found, do another round. */
794
795 return FALSE; /* Remove timer source on every other error / status. */
796#endif
797}
798
799/**
800 * Release logger callback.
801 *
802 * @return IPRT status code.
803 * @param pLoggerRelease
804 * @param enmPhase
805 * @param pfnLog
806 */
807static void vboxGreeterLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
808{
809 /* Some introductory information. */
810 static RTTIMESPEC s_TimeSpec;
811 char szTmp[256];
812 if (enmPhase == RTLOGPHASE_BEGIN)
813 RTTimeNow(&s_TimeSpec);
814 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
815
816 switch (enmPhase)
817 {
818 case RTLOGPHASE_BEGIN:
819 {
820 pfnLog(pLoggerRelease,
821 "vbox-greeter %s r%s (verbosity: %d) %s (%s %s) release log\n"
822 "Log opened %s\n",
823 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_iVerbosity, VBOX_BUILD_TARGET,
824 __DATE__, __TIME__, szTmp);
825
826 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
827 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
828 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
829 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
830 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
831 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
832 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
833 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
834 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
835 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
836 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
837
838 /* the package type is interesting for Linux distributions */
839 char szExecName[RTPATH_MAX];
840 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
841 pfnLog(pLoggerRelease,
842 "Executable: %s\n"
843 "Process ID: %u\n"
844 "Package type: %s"
845#ifdef VBOX_OSE
846 " (OSE)"
847#endif
848 "\n",
849 pszExecName ? pszExecName : "unknown",
850 RTProcSelf(),
851 VBOX_PACKAGE_STRING);
852 break;
853 }
854
855 case RTLOGPHASE_PREROTATE:
856 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
857 break;
858
859 case RTLOGPHASE_POSTROTATE:
860 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
861 break;
862
863 case RTLOGPHASE_END:
864 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
865 break;
866
867 default:
868 /* nothing */;
869 }
870}
871
872/**
873 * Creates the default release logger outputting to the specified file.
874 *
875 * @return IPRT status code.
876 * @param pszLogFile Filename for log output. Optional.
877 */
878static int vboxGreeterLogCreate(const char *pszLogFile)
879{
880 /* Create release logger (stdout + file). */
881 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
882 RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
883#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
884 fFlags |= RTLOGFLAGS_USECRLF;
885#endif
886 char szError[RTPATH_MAX + 128] = "";
887 int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
888 "VBOXGREETER_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
889 RTLOGDEST_STDOUT,
890 vboxGreeterLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
891 szError, sizeof(szError), pszLogFile);
892 if (RT_SUCCESS(rc))
893 {
894 /* register this logger as the release logger */
895 RTLogRelSetDefaultInstance(g_pLoggerRelease);
896
897 /* Explicitly flush the log in case of VBOXGREETER_RELEASE_LOG_FLAGS=buffered. */
898 RTLogFlush(g_pLoggerRelease);
899 }
900
901 return rc;
902}
903
904static void vboxGreeterLogDestroy(void)
905{
906 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
907}
908
909static int vboxGreeterUsage(void)
910{
911 RTPrintf("Usage:\n"
912 " %-12s [-h|-?|--help] [-F|--logfile <file>]\n"
913 " [-v|--verbose] [-V|--version]\n", g_pszProgName);
914
915 RTPrintf("\n"
916 " Copyright (C) 2012-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
917
918 return RTEXITCODE_SYNTAX;
919}
920
921int main(int argc, char **argv)
922{
923 int rc = RTR3InitExe(argc, &argv, 0);
924 if (RT_FAILURE(rc))
925 return RTMsgInitFailure(rc);
926 g_pszProgName = RTPathFilename(argv[0]);
927
928 static const RTGETOPTDEF s_aOptions[] =
929 {
930 { "--logfile", 'F', RTGETOPT_REQ_STRING },
931 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
932 { "--version", 'V', RTGETOPT_REQ_NOTHING }
933 };
934
935 char szLogFile[RTPATH_MAX + 128] = "";
936
937 int ch;
938 RTGETOPTUNION ValueUnion;
939 RTGETOPTSTATE GetState;
940 RTGetOptInit(&GetState, argc, argv,
941 s_aOptions, RT_ELEMENTS(s_aOptions),
942 1 /*iFirst*/, RTGETOPTINIT_FLAGS_OPTS_FIRST);
943
944 while ( (ch = RTGetOpt(&GetState, &ValueUnion))
945 && RT_SUCCESS(rc))
946 {
947 /* For options that require an argument, ValueUnion has received the value. */
948 switch (ch)
949 {
950 case 'F':
951 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", ValueUnion.psz))
952 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to get prepare log file name");
953 break;
954
955 case 'h':
956 case '?':
957 return vboxGreeterUsage();
958
959 case 'v': /* Raise verbosity. */
960 g_iVerbosity++;
961 break;
962
963 case 'V': /* Print version and exit. */
964 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
965 return RTEXITCODE_SUCCESS;
966 break; /* Never reached. */
967
968 default:
969 return RTGetOptPrintError(ch, &ValueUnion);
970 }
971 }
972
973 if (RT_FAILURE(rc))
974 return RTEXITCODE_SYNTAX;
975
976 rc = VbglR3InitUser();
977 if (RT_FAILURE(rc))
978 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to init Vbgl (%Rrc)", rc);
979
980 rc = vboxGreeterLogCreate(strlen(szLogFile) ? szLogFile : NULL);
981 if (RT_FAILURE(rc))
982 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
983 strlen(szLogFile) ? szLogFile : "<None>", rc);
984
985 vboxGreeterLog("init\n");
986
987 signal(SIGTERM, cb_sigterm);
988
989 /** @todo This function already is too long. Move code into
990 * functions. */
991
992 VBOXGREETERCTX ctx;
993 RT_ZERO(ctx);
994
995 /* UI parameters. */
996 uint32_t uBgColor = 0; /* The background color. */
997 uint32_t uLogonDlgHdrColor = 0;
998 uint32_t uLogonDlgBgColor = 0; /* The greeter's dialog color. */
999 uint32_t uLogonDlgBtnColor = 0; /* The greeter's button color. */
1000
1001 char szBannerPath[RTPATH_MAX];
1002
1003 /* By default most UI elements are shown. */
1004 uint32_t uOptsUI = VBOX_GREETER_UI_SHOW_RESTART
1005 | VBOX_GREETER_UI_SHOW_SHUTDOWN;
1006#ifdef VBOX_WITH_GUEST_PROPS
1007 uint32_t uClientId;
1008 rc = VbglR3GuestPropConnect(&uClientId);
1009 if (RT_SUCCESS(rc))
1010 {
1011 vboxGreeterLog("clientId=%RU32\n", uClientId);
1012
1013 ctx.uClientId = uClientId;
1014
1015 char szVal[256];
1016 int rc2 = vbox_read_prop(uClientId,
1017 "/VirtualBox/GuestAdd/Greeter/HideRestart",
1018 true /* Read-only on guest */,
1019 szVal, sizeof(szVal), NULL /* Timestamp. */);
1020 if ( RT_SUCCESS(rc2)
1021 && !RTStrICmp(szVal, "1"))
1022 {
1023 uOptsUI &= ~VBOX_GREETER_UI_SHOW_RESTART;
1024 }
1025
1026 rc2 = vbox_read_prop(uClientId,
1027 "/VirtualBox/GuestAdd/Greeter/HideShutdown",
1028 true /* Read-only on guest */,
1029 szVal, sizeof(szVal), NULL /* Timestamp. */);
1030 if ( RT_SUCCESS(rc2)
1031 && !RTStrICmp(szVal, "1"))
1032 {
1033 uOptsUI &= ~VBOX_GREETER_UI_SHOW_SHUTDOWN;
1034 }
1035
1036# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1037 /* Load the banner. */
1038 rc2 = vbox_read_prop(uClientId,
1039 "/VirtualBox/GuestAdd/Greeter/BannerPath",
1040 true /* Read-only on guest */,
1041 szBannerPath, sizeof(szBannerPath), NULL /* Timestamp. */);
1042 if (RT_SUCCESS(rc2))
1043 {
1044 if (RTFileExists(szBannerPath))
1045 {
1046 vboxGreeterLog("showing banner from '%s'\n", szBannerPath);
1047 uOptsUI |= VBOX_GREETER_UI_SHOW_BANNER;
1048 }
1049 else
1050 vboxGreeterLog("warning: unable to find banner at '%s', skipping\n", szBannerPath);
1051 }
1052# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */
1053
1054 /* Use theming?. */
1055 rc2 = vbox_read_prop(uClientId,
1056 "/VirtualBox/GuestAdd/Greeter/UseTheming",
1057 true /* Read-only on guest */,
1058 szVal, sizeof(szVal), NULL /* Timestamp. */);
1059 if ( RT_SUCCESS(rc2)
1060 && !RTStrICmp(szVal, "1"))
1061 {
1062 vboxGreeterLog("custom theming enabled\n");
1063 uOptsUI |= VBOX_GREETER_UI_USE_THEMING;
1064 }
1065
1066 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1067 {
1068 /* Get background color. */
1069 rc2 = vbox_read_prop(uClientId,
1070 "/VirtualBox/GuestAdd/Greeter/Theme/BackgroundColor",
1071 true /* Read-only on guest */,
1072 szVal, sizeof(szVal), NULL /* Timestamp. */);
1073 if (RT_SUCCESS(rc2))
1074 {
1075 uBgColor = strtol(szVal, NULL,
1076 /* Change conversion base when having a 0x prefix. */
1077 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1078 }
1079
1080 /* Logon dialog. */
1081
1082 /* Get header color. */
1083 rc2 = vbox_read_prop(uClientId,
1084 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/HeaderColor",
1085 true /* Read-only on guest */,
1086 szVal, sizeof(szVal), NULL /* Timestamp. */);
1087 if (RT_SUCCESS(rc2))
1088 {
1089 uLogonDlgHdrColor = strtol(szVal, NULL,
1090 /* Change conversion base when having a 0x prefix. */
1091 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1092 }
1093
1094 /* Get dialog color. */
1095 rc2 = vbox_read_prop(uClientId,
1096 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/BackgroundColor",
1097 true /* Read-only on guest */,
1098 szVal, sizeof(szVal), NULL /* Timestamp. */);
1099 if (RT_SUCCESS(rc2))
1100 {
1101 uLogonDlgBgColor = strtol(szVal, NULL,
1102 /* Change conversion base when having a 0x prefix. */
1103 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1104 }
1105
1106 /* Get button color. */
1107 rc2 = vbox_read_prop(uClientId,
1108 "/VirtualBox/GuestAdd/Greeter/Theme/LogonDialog/ButtonColor",
1109 true /* Read-only on guest */,
1110 szVal, sizeof(szVal), NULL /* Timestamp. */);
1111 if (RT_SUCCESS(rc2))
1112 {
1113 uLogonDlgBtnColor = strtol(szVal, NULL,
1114 /* Change conversion base when having a 0x prefix. */
1115 RTStrStr(szVal, "0x") == szVal ? 0 : 16);
1116 }
1117 }
1118 }
1119#endif
1120 vboxGreeterLog("UI options are: %RU32\n", uOptsUI);
1121
1122#ifdef VBOX_WITH_FLTK
1123 int rc2 = Fl::scheme("plastic");
1124 if (!rc2)
1125 vboxGreeterLog("warning: unable to set visual scheme\n");
1126
1127 Fl::visual(FL_DOUBLE | FL_INDEX);
1128 Fl_Double_Window *pWndMain = new Fl_Double_Window(Fl::w(), Fl::h(), "VirtualBox Guest Additions");
1129 AssertPtr(pWndMain);
1130 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1131 pWndMain->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uBgColor),
1132 VBOX_RGB_COLOR_GREEN(uBgColor),
1133 VBOX_RGB_COLOR_BLUE(uBgColor)));
1134 else /* Default colors. */
1135 pWndMain->color(fl_rgb_color(0x73, 0x7F, 0x8C));
1136
1137 Fl_Double_Window *pWndGreeter = new Fl_Double_Window(500, 350);
1138 AssertPtr(pWndGreeter);
1139 pWndGreeter->set_modal();
1140 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1141 pWndGreeter->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBgColor),
1142 VBOX_RGB_COLOR_GREEN(uLogonDlgBgColor),
1143 VBOX_RGB_COLOR_BLUE(uLogonDlgBgColor)));
1144 else /* Default colors. */
1145 pWndGreeter->color(fl_rgb_color(255, 255, 255));
1146
1147 uint32_t uOffsetX = 130;
1148 /**
1149 * For now we're using a simple Y offset for moving all elements
1150 * down if a banner needs to be shown on top of the greeter. Not
1151 * very clean but does the job. Use some more layouting stuff
1152 * when this gets more complex.
1153 */
1154 uint32_t uOffsetY = 80;
1155
1156# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1157 fl_register_images();
1158
1159 /** @todo Add basic image type detection based on file
1160 * extension. */
1161
1162 Fl_PNG_Image *pImgBanner = NULL;
1163 if (uOptsUI & VBOX_GREETER_UI_SHOW_BANNER)
1164 {
1165 pImgBanner = new Fl_PNG_Image(szBannerPath);
1166 AssertPtr(pImgBanner);
1167
1168 /** @todo Make the banner size configurable via guest
1169 * properties. For now it's hardcoded to 460 x 90px. */
1170 Fl_Box *pBoxBanner = new Fl_Box(20, uOffsetY, 460, 90, "");
1171 AssertPtr(pBoxBanner);
1172 pBoxBanner->image(pImgBanner);
1173
1174 uOffsetY = 120;
1175 }
1176# endif
1177
1178 Fl_Box *pLblHeader = new Fl_Box(FL_NO_BOX, 242, uOffsetY, 300, 20,
1179 "Desktop Login");
1180 AssertPtr(pLblHeader);
1181
1182 /** Note to use an own font:
1183 * Fl_Font myfnt = FL_FREE_FONT + 1;
1184 * Fl::set_font(myfnt, "MyFont"); */
1185 Fl_Font fntHeader = FL_FREE_FONT;
1186 Fl::set_font(fntHeader, "Courier");
1187
1188 pLblHeader->align(FL_ALIGN_LEFT);
1189 pLblHeader->labelfont(FL_BOLD);
1190 pLblHeader->labelsize(24);
1191 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1192 pLblHeader->labelcolor(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgHdrColor),
1193 VBOX_RGB_COLOR_GREEN(uLogonDlgHdrColor),
1194 VBOX_RGB_COLOR_BLUE(uLogonDlgHdrColor)));
1195 else /* Default color. */
1196 pLblHeader->labelcolor(fl_rgb_color(0x51, 0x5F, 0x77));
1197 uOffsetY += 40;
1198
1199 /** @todo Add basic NLS support. */
1200
1201 Fl_Input *pEdtUsername = new Fl_Input(uOffsetX, uOffsetY,
1202 300, 20, "User Name");
1203 AssertPtr(pEdtUsername);
1204 pEdtUsername->callback(cb_edt_username, &ctx);
1205 pEdtUsername->when(FL_WHEN_ENTER_KEY_ALWAYS);
1206 Fl::focus(pEdtUsername);
1207 ctx.pEdtUsername = pEdtUsername;
1208
1209 Fl_Secret_Input *pEdtPassword = new Fl_Secret_Input(uOffsetX, uOffsetY + 40,
1210 300, 20, "Password");
1211 AssertPtr(pEdtPassword);
1212 pEdtPassword->callback(cb_edt_password, &ctx);
1213 pEdtPassword->when(FL_WHEN_ENTER_KEY_ALWAYS);
1214 ctx.pEdtPassword = pEdtPassword;
1215
1216 Fl_Button *pBtnLogin = new Fl_Button(uOffsetX, uOffsetY + 70,
1217 100, 40, "Log In");
1218 AssertPtr(pBtnLogin);
1219 pBtnLogin->callback(cb_btn_login, &ctx);
1220 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1221 pBtnLogin->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor),
1222 VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor),
1223 VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor)));
1224 else /* Default color. */
1225 pBtnLogin->color(fl_rgb_color(255, 255, 255));
1226 ctx.pBtnLogin = pBtnLogin;
1227
1228 Fl_Menu_Button *pBtnMenu = new Fl_Menu_Button(uOffsetX + 120, uOffsetY + 70,
1229 100, 40, "Options");
1230 AssertPtr(pBtnMenu);
1231 pBtnMenu->callback(cb_btn_menu, &ctx);
1232 if (uOptsUI & VBOX_GREETER_UI_USE_THEMING)
1233 pBtnMenu->color(fl_rgb_color(VBOX_RGB_COLOR_RED(uLogonDlgBtnColor),
1234 VBOX_RGB_COLOR_GREEN(uLogonDlgBtnColor),
1235 VBOX_RGB_COLOR_BLUE(uLogonDlgBtnColor)));
1236 else /* Default color. */
1237 pBtnMenu->color(fl_rgb_color(255, 255, 255));
1238
1239 if (uOptsUI & VBOX_GREETER_UI_SHOW_RESTART)
1240 pBtnMenu->add("Restart", "" /* Shortcut */, cb_btn_restart, &ctx, 0 /* Flags */);
1241 if (uOptsUI & VBOX_GREETER_UI_SHOW_SHUTDOWN)
1242 pBtnMenu->add("Shutdown", "" /* Shortcut */, cb_btn_shutdown, &ctx, 0 /* Flags */);
1243
1244 char szLabel[255];
1245 RTStrPrintf(szLabel, sizeof(szLabel), "Oracle VM VirtualBox Guest Additions %sr%s",
1246 RTBldCfgVersion(), RTBldCfgRevisionStr());
1247 Fl_Box *pLblInfo = new Fl_Box(FL_NO_BOX, 90, uOffsetY + 150,
1248 300, 20, szLabel);
1249 AssertPtr(pLblInfo);
1250 ctx.pLblInfo = pLblInfo;
1251
1252 pWndGreeter->end();
1253 pWndGreeter->position((Fl::w() - pWndGreeter->w()) / 2,
1254 (Fl::h() - pWndGreeter->h()) / 2);
1255
1256 pWndMain->fullscreen();
1257 pWndMain->show(argc, argv);
1258 pWndMain->end();
1259
1260 pWndGreeter->show();
1261#else
1262 gtk_init(&argc, &argv);
1263
1264 /* Set default cursor */
1265 gdk_window_set_cursor(gdk_get_default_root_window(), gdk_cursor_new(GDK_LEFT_PTR));
1266
1267 GError *pError = NULL;
1268 GtkBuilder *pBuilder = gtk_builder_new();
1269 AssertPtr(pBuilder);
1270 if (!gtk_builder_add_from_file(pBuilder, "/usr/share/xgreeters/vbox-greeter.ui", &pError))
1271 {
1272 AssertPtr(pError);
1273 vboxGreeterError("unable to load UI: %s", pError->message);
1274 return RTEXITCODE_FAILURE;
1275 }
1276
1277 GtkWindow *pWndGreeter = GTK_WINDOW(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_WND_GREETER));
1278 AssertPtr(pWndGreeter);
1279 GtkButton *pBtnLogin = GTK_BUTTON(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_BTN_LOGIN));
1280 AssertPtr(pBtnLogin);
1281 GtkLabel *pLblInfo = GTK_LABEL(gtk_builder_get_object(pBuilder, VBOX_GREETER_UI_LBL_INFO));
1282 AssertPtr(pLblInfo);
1283
1284 ctx.pBuilder = pBuilder;
1285
1286 g_signal_connect(G_OBJECT(pBtnLogin), "clicked", G_CALLBACK(cb_btn_login), &ctx);
1287
1288 GdkRectangle rectScreen;
1289 gdk_screen_get_monitor_geometry(gdk_screen_get_default(), gdk_screen_get_primary_monitor(gdk_screen_get_default()), &rectScreen);
1290 vboxGreeterLog("monitor (default) is %dx%d\n", rectScreen.width, rectScreen.height);
1291
1292 gint iWndX, iWndY;
1293 gtk_window_get_default_size(pWndGreeter, &iWndX, &iWndY);
1294 vboxGreeterLog("greeter is %dx%d\n", iWndX, iWndY);
1295
1296 gtk_window_move(pWndGreeter,
1297 (rectScreen.width / 2) - (iWndX / 2),
1298 (rectScreen.height / 2) - (iWndY / 2));
1299 gtk_widget_show(GTK_WIDGET(pWndGreeter));
1300
1301 g_clear_error(&pError);
1302#endif
1303
1304 /* GType is needed in any case (for LightDM), whether we
1305 * use GTK3 or not. */
1306 g_type_init();
1307
1308 GMainLoop *pMainLoop = g_main_loop_new(NULL, FALSE /* Not yet running */);
1309 AssertPtr(pMainLoop);
1310
1311 LightDMGreeter *pGreeter = lightdm_greeter_new();
1312 AssertPtr(pGreeter);
1313
1314 g_signal_connect(pGreeter, "show-prompt", G_CALLBACK(cb_lightdm_show_prompt), &ctx);
1315 g_signal_connect(pGreeter, "show-message", G_CALLBACK(cb_lightdm_show_message), &ctx);
1316 g_signal_connect(pGreeter, "authentication-complete", G_CALLBACK(cb_lightdm_auth_complete), &ctx);
1317
1318 ctx.pGreeter = pGreeter;
1319
1320 if (!lightdm_greeter_connect_sync(pGreeter, NULL))
1321 {
1322 vboxGreeterError("unable to connect to LightDM server, aborting\n");
1323 return RTEXITCODE_FAILURE;
1324 }
1325
1326 vboxGreeterLog("connected to LightDM server\n");
1327
1328#ifdef VBOX_WITH_GUEST_PROPS
1329 bool fCheckCreds = false;
1330 if (uClientId)
1331 {
1332 char szVal[256];
1333 rc = vbox_read_prop(uClientId,
1334 "/VirtualBox/GuestAdd/PAM/CredsWait",
1335 true /* Read-only on guest */,
1336 szVal, sizeof(szVal), NULL /* Timestamp. */);
1337 if (RT_SUCCESS(rc))
1338 {
1339 /* All calls which are checked against rc2 are not critical, e.g. it does
1340 * not matter if they succeed or not. */
1341 uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */
1342 rc2 = vbox_read_prop(uClientId,
1343 "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout",
1344 true /* Read-only on guest */,
1345 szVal, sizeof(szVal), NULL /* Timestamp. */);
1346 if (RT_SUCCESS(rc2))
1347 {
1348 uTimeoutMS = RTStrToUInt32(szVal);
1349 if (!uTimeoutMS)
1350 {
1351 vboxGreeterError("pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n");
1352 uTimeoutMS = RT_INDEFINITE_WAIT;
1353 }
1354 else
1355 uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */
1356 }
1357
1358 ctx.uTimeoutMS = uTimeoutMS;
1359
1360 rc2 = vbox_read_prop(uClientId,
1361 "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting",
1362 true /* Read-only on guest */,
1363 szVal, sizeof(szVal), NULL /* Timestamp. */);
1364 if (RT_SUCCESS(rc2))
1365#ifdef VBOX_WITH_FLTK
1366 pLblInfo->label(szVal);
1367#else
1368 gtk_label_set_text(pLblInfo, szVal);
1369#endif
1370 /* Get initial timestamp so that we can compare the time
1371 * whether the value has been changed or not in our event callback. */
1372 vbox_read_prop(uClientId,
1373 "/VirtualBox/GuestAdd/PAM/CredsWaitAbort",
1374 true /* Read-only on guest */,
1375 szVal, sizeof(szVal), &ctx.uTsAbort);
1376
1377 if (RT_SUCCESS(rc))
1378 {
1379 /* Before we actuall wait for credentials just make sure we didn't already get credentials
1380 * set so that we can skip waiting for them ... */
1381 rc2 = vboxGreeterCheckCreds(&ctx);
1382 if (rc2 == VERR_NOT_FOUND)
1383 {
1384 /* Get current time stamp to later calculate rest of timeout left. */
1385 ctx.uStartMS = RTTimeMilliTS();
1386
1387 fCheckCreds = true;
1388 }
1389 }
1390 }
1391
1392 /* Start the timer to check credentials availability. */
1393 if (fCheckCreds)
1394#ifdef VBOX_WITH_FLTK
1395 Fl::add_timeout(0.5 /* 500 ms */, cb_check_creds, &ctx);
1396#else
1397 g_timeout_add(500 /* ms */, (GSourceFunc)cb_check_creds, &ctx);
1398#endif
1399 }
1400#endif /* VBOX_WITH_GUEST_PROPS */
1401
1402#ifdef VBOX_WITH_FLTK
1403 /*
1404 * Do own GDK main loop processing because FLTK also needs
1405 * to have the chance of processing its events.
1406 */
1407 GMainContext *pMainCtx = g_main_context_default();
1408 AssertPtr(pMainCtx);
1409
1410 for (;;)
1411 {
1412 g_main_context_iteration(pMainCtx,
1413 FALSE /* No blocking */);
1414 Fl::check();
1415 }
1416
1417 g_main_context_unref(pMainCtx);
1418
1419# ifdef VBOX_GREETER_WITH_PNG_SUPPORT
1420 if (pImgBanner)
1421 {
1422 delete pImgBanner; /* Call destructor to free bitmap data. */
1423 pImgBanner = NULL;
1424 }
1425# endif /* VBOX_GREETER_WITH_PNG_SUPPORT */
1426#else
1427 gtk_main();
1428#endif
1429
1430 vboxGreeterLog("terminating\n");
1431
1432 rc2 = VbglR3GuestPropDisconnect(uClientId);
1433 AssertRC(rc2);
1434
1435 VbglR3Term();
1436
1437 vboxGreeterLog("terminated with rc=%Rrc\n", rc);
1438
1439 vboxGreeterLogDestroy();
1440
1441 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1442}
1443
1444#ifdef DEBUG
1445DECLEXPORT(void) RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1446{
1447 RTAssertMsg1(pszExpr, uLine, pszFile, pszFunction);
1448}
1449#endif
1450
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette