VirtualBox

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

Last change on this file since 67663 was 63433, checked in by vboxsync, 8 years ago

vbox-greeter.cpp: unused function

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