1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5    Copyright (C) 2016-2016 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21  */
22 /*
23  * Kern Sibbald, August 2007
24  *
25  * Note, some of the original Bareos Windows startup and service handling code
26  * was derived from VNC code that was used in apcupsd then ported to
27  * Bareos.  However, since then the code has been significantly enhanced
28  * and largely rewritten.
29  *
30  * Evidently due to the nature of Windows startup code and service
31  * handling code, certain similarities remain. Thanks to the original
32  * VNC authors.
33  *
34  * This is a generic main routine, which is used by all three
35  * of the daemons. Each one compiles it with slightly different
36  * #defines.
37  */
38 
39 #include "include/bareos.h"
40 #include "win32.h"
41 #include "who.h"
42 #include <signal.h>
43 #include <pthread.h>
44 
45 #undef  _WIN32_IE
46 #ifdef MINGW64
47 # define _WIN32_IE 0x0501
48 #else
49 # define _WIN32_IE 0x0401
50 #endif  // MINGW64
51 #undef  _WIN32_WINNT
52 #define _WIN32_WINNT 0x0501
53 #include <commctrl.h>
54 
55 
56 /* Globals */
57 HINSTANCE appInstance;
58 DWORD mainthreadId;
59 bool opt_debug = false;
60 bool have_service_api;
61 DWORD service_thread_id = 0;
62 char win_os[300];
63 
64 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz);
65 
66 
67 #define MAX_COMMAND_ARGS 100
68 static char *command_args[MAX_COMMAND_ARGS] = { (char *)LC_APP_NAME, NULL };
69 static int num_command_args = 1;
70 static pid_t main_pid;
71 static pthread_t main_tid;
72 
73 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
74 
75 /*
76  *
77  * Main Windows entry point.
78  *
79  * We parse the command line and either calls the main App
80  *   or starts up the service.
81  */
WinMain(HINSTANCE Instance,HINSTANCE,PSTR CmdLine,int)82 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
83                    int /*show*/)
84 {
85    char *cmdLine = CmdLine;
86    char *wordPtr, *tempPtr;
87    int i, quote;
88    OSVERSIONINFO osversioninfo;
89    osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
90 
91 
92    /* Save the application instance and main thread id */
93    appInstance = Instance;
94    mainthreadId = GetCurrentThreadId();
95 
96    if (GetVersionEx(&osversioninfo) &&
97        osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
98       have_service_api = true;
99    }
100 
101    GetWindowsVersionString(win_os, sizeof(win_os));
102 
103    main_pid = getpid();
104    main_tid = pthread_self();
105 
106    INITCOMMONCONTROLSEX initCC = {
107       sizeof(INITCOMMONCONTROLSEX),
108       ICC_STANDARD_CLASSES
109    };
110 
111    InitCommonControlsEx(&initCC);
112 
113    /*
114     * Funny things happen with the command line if the
115     * execution comes from c:/Program Files/bareos/bareos.exe
116     * We get a command line like: Files/bareos/bareos.exe" options
117     * I.e. someone stops scanning command line on a space, not
118     * realizing that the filename is quoted!!!!!!!!!!
119     * So if first character is not a double quote and
120     * the last character before first space is a double
121     * quote, we throw away the junk.
122     */
123 
124    wordPtr = cmdLine;
125    while (*wordPtr && *wordPtr != ' ')
126       wordPtr++;
127    if (wordPtr > cmdLine)      /* backup to char before space */
128       wordPtr--;
129    /* if first character is not a quote and last is, junk it */
130    if (*cmdLine != '"' && *wordPtr == '"') {
131       cmdLine = wordPtr + 1;
132    }
133 
134    /*
135     * Build Unix style argc *argv[] for the main "Unix" code
136     *  stripping out any Windows options
137     */
138 
139    /* Don't NULL command_args[0] !!! */
140    for (i=1;i<MAX_COMMAND_ARGS;i++) {
141       command_args[i] = NULL;
142    }
143 
144    char *pszArgs = bstrdup(cmdLine);
145    wordPtr = pszArgs;
146    quote = 0;
147    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
148       wordPtr++;
149    if (*wordPtr == '\"') {
150       quote = 1;
151       wordPtr++;
152    } else if (*wordPtr == '/') {
153       /* Skip Windows options */
154       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
155          wordPtr++;
156       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
157          wordPtr++;
158    }
159    if (*wordPtr) {
160       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
161          tempPtr = wordPtr;
162          if (quote) {
163             while (*tempPtr && *tempPtr != '\"')
164                tempPtr++;
165             quote = 0;
166          } else {
167             while (*tempPtr && *tempPtr != ' ')
168             tempPtr++;
169          }
170          if (*tempPtr)
171             *(tempPtr++) = '\0';
172          command_args[num_command_args++] = wordPtr;
173          wordPtr = tempPtr;
174          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
175             wordPtr++;
176          if (*wordPtr == '\"') {
177             quote = 1;
178             wordPtr++;
179          }
180       }
181    }
182 
183    /*
184     * Now process Windows command line options. Most of these options
185     *  are single shot -- i.e. we accept one option, do something and
186     *  Terminate.
187     */
188    for (i = 0; i < (int)strlen(cmdLine); i++) {
189       char *p = &cmdLine[i];
190 
191       if (*p <= ' ') {
192          continue;                    /* toss junk */
193       }
194 
195       if (*p != '/') {
196          break;                       /* syntax error */
197       }
198 
199       /* Start as a service? */
200       if (strncasecmp(p, "/service", 8) == 0) {
201          return bareosServiceMain();      /* yes, run as a service */
202       }
203 
204       /* Stop any running copy? */
205       if (strncasecmp(p, "/kill", 5) == 0) {
206          return stopRunningBareos();
207       }
208 
209       /* Run app as user program? */
210       if (strncasecmp(p, "/run", 4) == 0) {
211          return BareosAppMain();         /* yes, run as a user program */
212       }
213 
214       /* Install Bareos in registry? */
215       if (strncasecmp(p, "/install", 8) == 0) {
216          return installService(p+8);    /* Pass command options */
217       }
218 
219       /* Remove Bareos registry entry? */
220       if (strncasecmp(p, "/remove", 7) == 0) {
221          return removeService();
222       }
223 
224       /* Set debug mode? -- causes more dialogs to be displayed */
225       if (strncasecmp(p, "/debug", 6) == 0) {
226          opt_debug = true;
227          i += 6;                /* skip /debug */
228          continue;
229       }
230 
231       /* Display help? -- displays usage */
232       if (strncasecmp(p, "/help", 5) == 0) {
233          MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
234          return 0;
235       }
236 
237       MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
238 
239       /* Show the usage dialog */
240       MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
241 
242       return 1;
243    }
244    return BareosAppMain();
245 }
246 
247 /*
248  * Minimalist winproc when don't have tray monitor
249  */
bacWinProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)250 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
251 {
252    switch (iMsg) {
253    case WM_DESTROY:
254       PostQuitMessage(0);
255       return 0;
256    }
257    return DefWindowProc(hwnd, iMsg, wParam, lParam);
258 }
259 
260 /*
261  * Called as a thread from BareosAppMain()
262  * Here we handle the Windows messages
263  */
Main_Msg_Loop(LPVOID lpwThreadParam)264 void *Main_Msg_Loop(LPVOID lpwThreadParam)
265 {
266    MSG msg;
267 
268    pthread_detach(pthread_self());
269 
270    /*
271     * Since we are the only thread with a message loop
272     * mark ourselves as the service thread so that
273     * we can receive all the window events.
274     */
275    service_thread_id = GetCurrentThreadId();
276 
277    /* Create a window to handle Windows messages */
278    WNDCLASSEX baclass;
279 
280    baclass.cbSize         = sizeof(baclass);
281    baclass.style          = 0;
282    baclass.lpfnWndProc    = bacWinProc;
283    baclass.cbClsExtra     = 0;
284    baclass.cbWndExtra     = 0;
285    baclass.hInstance      = appInstance;
286    baclass.hIcon          = NULL;
287    baclass.hCursor        = NULL;
288    baclass.hbrBackground  = NULL;
289    baclass.lpszMenuName   = NULL;
290    baclass.lpszClassName  = APP_NAME;
291    baclass.hIconSm        = NULL;
292 
293    RegisterClassEx(&baclass);
294 
295    if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
296                 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
297                 NULL, NULL, appInstance, NULL) == NULL) {
298       PostQuitMessage(0);
299    }
300 
301    /* Now enter the Windows message handling loop until told to quit! */
302    while (GetMessage(&msg, NULL, 0,0)) {
303       TranslateMessage(&msg);
304       DispatchMessage(&msg);
305    }
306 
307    /* If we get here, we are shutting down */
308 
309    if (have_service_api) {
310       /* Mark that we're no longer running */
311       service_thread_id = 0;
312       /* Tell the service manager that we've stopped. */
313       ReportStatus(SERVICE_STOPPED, service_error, 0);
314    }
315    /* Tell main "Unix" program to go away */
316    TerminateApp(0);
317 
318    /* Should not get here */
319    pthread_kill(main_tid, SIGTERM);   /* ask main thread to Terminate */
320    sleep(1);
321    kill(main_pid, SIGTERM);           /* kill main thread */
322    _exit(0);
323 }
324 
325 
326 /*
327  * This is the main routine for Bareos when running as an application,
328  *  or after the service has started up.
329  */
BareosAppMain()330 int BareosAppMain()
331 {
332    pthread_t tid;
333    DWORD dwCharsWritten;
334 
335    OSDependentInit();
336 
337    /* If no arguments were given then just run */
338    if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
339       if (opt_debug) {
340          AllocConsole();
341       }
342    }
343    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
344 
345    /* Startup networking */
346    WSA_Init();
347 
348    /* Set this process to be the last application to be shut down. */
349    if (p_SetProcessShutdownParameters) {
350       p_SetProcessShutdownParameters(0x100, 0);
351    }
352 
353    /* Create a thread to handle the Windows messages */
354    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
355 
356    /* Call the Unix Bareos daemon */
357    BareosMain(num_command_args, command_args);
358    PostQuitMessage(0);                /* Terminate our main message loop */
359 
360    WSACleanup();
361    _exit(0);
362 }
363 
364 
PauseMsg(const char * file,const char * func,int line,const char * msg)365 void PauseMsg(const char *file, const char *func, int line, const char *msg)
366 {
367    char buf[1000];
368    if (msg) {
369       Bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
370    } else {
371       Bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
372    }
373    MessageBox(NULL, buf, "Pause", MB_OK);
374 }
375 
376 #include <windows.h>
377 #include <tchar.h>
378 #include <stdio.h>
379 
380 #ifndef PRODUCT_UNLICENSED
381 #define PRODUCT_UNLICENSED 0xABCDABCD
382 #define PRODUCT_BUSINESS 0x00000006
383 #define PRODUCT_BUSINESS_N 0x00000010
384 #define PRODUCT_CLUSTER_SERVER 0x00000012
385 #define PRODUCT_DATACENTER_SERVER 0x00000008
386 #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C
387 #define PRODUCT_DATACENTER_SERVER_CORE_V 0x00000027
388 #define PRODUCT_DATACENTER_SERVER_V 0x00000025
389 #define PRODUCT_ENTERPRISE 0x00000004
390 #define PRODUCT_ENTERPRISE_E 0x00000046
391 #define PRODUCT_ENTERPRISE_N 0x0000001B
392 #define PRODUCT_ENTERPRISE_SERVER 0x0000000A
393 #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E
394 #define PRODUCT_ENTERPRISE_SERVER_CORE_V 0x00000029
395 #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F
396 #define PRODUCT_ENTERPRISE_SERVER_V 0x00000026
397 #define PRODUCT_HOME_BASIC 0x00000002
398 #define PRODUCT_HOME_BASIC_E 0x00000043
399 #define PRODUCT_HOME_BASIC_N 0x00000005
400 #define PRODUCT_HOME_PREMIUM 0x00000003
401 #define PRODUCT_HOME_PREMIUM_E 0x00000044
402 #define PRODUCT_HOME_PREMIUM_N 0x0000001A
403 #define PRODUCT_HYPERV 0x0000002A
404 #define PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT 0x0000001E
405 #define PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING 0x00000020
406 #define PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY 0x0000001F
407 #define PRODUCT_PROFESSIONAL 0x00000030
408 #define PRODUCT_PROFESSIONAL_E 0x00000045
409 #define PRODUCT_PROFESSIONAL_N 0x00000031
410 #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018
411 #define PRODUCT_SERVER_FOR_SMALLBUSINESS_V 0x00000023
412 #define PRODUCT_SERVER_FOUNDATION 0x00000021
413 #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009
414 #define PRODUCT_SOLUTION_EMBEDDEDSERVER 0x00000038
415 #define PRODUCT_STANDARD_SERVER 0x00000007
416 #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D
417 #define PRODUCT_STANDARD_SERVER_CORE_V 0x00000028
418 #define PRODUCT_STANDARD_SERVER_V 0x00000024
419 #define PRODUCT_STARTER 0x0000000B
420 #define PRODUCT_STARTER_E 0x00000042
421 #define PRODUCT_STARTER_N 0x0000002F
422 #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017
423 #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014
424 #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015
425 #define PRODUCT_STORAGE_WORKGROUP_SERVER  0x00000016
426 #define PRODUCT_UNDEFINED 0x00000000
427 #define PRODUCT_ULTIMATE 0x00000001
428 #define PRODUCT_ULTIMATE_E 0x00000047
429 #define PRODUCT_ULTIMATE_N 0x0000001C
430 #define PRODUCT_WEB_SERVER 0x00000011
431 #define PRODUCT_WEB_SERVER_CORE 0x0000001D
432 
433 #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19
434 #define SM_SERVERR2 89
435 #define VER_SERVER_NT 0x80000000
436 
437 #endif
438 
439 #ifndef PRODUCT_PROFESSIONAL
440 #define PRODUCT_PROFESSIONAL 0x00000030
441 #endif
442 #ifndef VER_SUITE_STORAGE_SERVER
443 #define VER_SUITE_STORAGE_SERVER 0x00002000
444 #endif
445 #ifndef VER_SUITE_COMPUTE_SERVER
446 #define VER_SUITE_COMPUTE_SERVER 0x00004000
447 #endif
448 
449 /* Unknown value */
450 #undef VER_SUITE_WH_SERVER
451 #define VER_SUITE_WH_SERVER -1
452 
453 
454 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
455 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
456 
457 /*
458  * Get Windows version display string
459  */
GetWindowsVersionString(LPTSTR osbuf,int maxsiz)460 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz)
461 {
462    OSVERSIONINFOEX osvi;
463    SYSTEM_INFO si;
464    PGNSI pGNSI;
465    PGPI pGPI;
466    BOOL bOsVersionInfoEx;
467    DWORD dwType;
468 
469    memset(&si, 0, sizeof(SYSTEM_INFO));
470    memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
471 
472    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
473 
474    if (!(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)))
475       return 1;
476 
477    // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
478 
479    pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
480            "GetNativeSystemInfo");
481    if (pGNSI) {
482       pGNSI(&si);
483    } else {
484       GetSystemInfo(&si);
485    }
486 
487    if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion > 4) {
488       bstrncpy(osbuf, TEXT("Microsoft "), maxsiz);
489 
490       /*
491        * Test for the specific product.
492        */
493       switch (osvi.dwMajorVersion) {
494       case 6:
495          switch (osvi.dwMinorVersion) {
496          case 0:
497             if (osvi.wProductType == VER_NT_WORKSTATION) {
498                 bstrncat(osbuf, TEXT("Windows Vista "), maxsiz);
499             } else {
500                 bstrncat(osbuf, TEXT("Windows Server 2008 "), maxsiz);
501             }
502             break;
503          case 1:
504             if (osvi.wProductType == VER_NT_WORKSTATION) {
505                 bstrncat(osbuf, TEXT("Windows 7 "), maxsiz);
506             } else {
507                 bstrncat(osbuf, TEXT("Windows Server 2008 R2 "), maxsiz);
508             }
509             break;
510          case 2:
511             if (osvi.wProductType == VER_NT_WORKSTATION) {
512                 bstrncat(osbuf, TEXT("Windows 8 "), maxsiz);
513             } else {
514                 bstrncat(osbuf, TEXT("Windows Server 2012 "), maxsiz);
515             }
516             break;
517          default:
518             bstrncat(osbuf, TEXT("Windows Unknown Release "), maxsiz);
519             break;
520          }
521 
522          pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
523          if (pGPI) {
524             pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
525          } else {
526             dwType = PRODUCT_HOME_BASIC;
527          }
528 
529          switch (dwType) {
530          case PRODUCT_ULTIMATE:
531             bstrncat(osbuf, TEXT("Ultimate Edition"), maxsiz);
532             break;
533          case PRODUCT_PROFESSIONAL:
534             bstrncat(osbuf, TEXT("Professional"), maxsiz);
535             break;
536          case PRODUCT_HOME_PREMIUM:
537             bstrncat(osbuf, TEXT("Home Premium Edition"), maxsiz);
538             break;
539          case PRODUCT_HOME_BASIC:
540             bstrncat(osbuf, TEXT("Home Basic Edition"), maxsiz);
541             break;
542          case PRODUCT_ENTERPRISE:
543             bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
544             break;
545          case PRODUCT_BUSINESS:
546             bstrncat(osbuf, TEXT("Business Edition"), maxsiz);
547             break;
548          case PRODUCT_STARTER:
549             bstrncat(osbuf, TEXT("Starter Edition"), maxsiz);
550             break;
551          case PRODUCT_CLUSTER_SERVER:
552             bstrncat(osbuf, TEXT("Cluster Server Edition"), maxsiz);
553             break;
554          case PRODUCT_DATACENTER_SERVER:
555             bstrncat(osbuf, TEXT("Datacenter Edition"), maxsiz);
556             break;
557          case PRODUCT_DATACENTER_SERVER_CORE:
558             bstrncat(osbuf, TEXT("Datacenter Edition (core installation)"), maxsiz);
559             break;
560          case PRODUCT_ENTERPRISE_SERVER:
561             bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
562             break;
563          case PRODUCT_ENTERPRISE_SERVER_CORE:
564             bstrncat(osbuf, TEXT("Enterprise Edition (core installation)"), maxsiz);
565             break;
566          case PRODUCT_ENTERPRISE_SERVER_IA64:
567             bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems"), maxsiz);
568             break;
569          case PRODUCT_SMALLBUSINESS_SERVER:
570             bstrncat(osbuf, TEXT("Small Business Server"), maxsiz);
571             break;
572          case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
573             bstrncat(osbuf, TEXT("Small Business Server Premium Edition"), maxsiz);
574             break;
575          case PRODUCT_STANDARD_SERVER:
576             bstrncat(osbuf, TEXT("Standard Edition"), maxsiz);
577             break;
578          case PRODUCT_STANDARD_SERVER_CORE:
579             bstrncat(osbuf, TEXT("Standard Edition (core installation)"), maxsiz);
580             break;
581          case PRODUCT_WEB_SERVER:
582             bstrncat(osbuf, TEXT("Web Server Edition"), maxsiz);
583             break;
584          }
585          break;
586       case 5:
587          switch (osvi.dwMinorVersion) {
588          case 2:
589             if (GetSystemMetrics(SM_SERVERR2)) {
590                bstrncat(osbuf, TEXT("Windows Server 2003 R2 "), maxsiz);
591             } else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER) {
592                bstrncat(osbuf, TEXT("Windows Storage Server 2003"), maxsiz);
593             } else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER) {
594                bstrncat(osbuf, TEXT("Windows Home Server"), maxsiz);
595             } else if (osvi.wProductType == VER_NT_WORKSTATION &&
596                        si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
597                bstrncat(osbuf, TEXT("Windows XP Professional x64 Edition"), maxsiz);
598             } else {
599                bstrncat(osbuf, TEXT("Windows Server 2003 "), maxsiz);
600             }
601 
602             /*
603              * Test for the server type.
604              */
605             if (osvi.wProductType != VER_NT_WORKSTATION) {
606                if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
607                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
608                       bstrncat(osbuf, TEXT("Datacenter Edition for Itanium-based Systems"), maxsiz);
609                    } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
610                       bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems"), maxsiz);
611                    }
612                } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
613                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
614                       bstrncat(osbuf, TEXT("Datacenter x64 Edition"), maxsiz);
615                    } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
616                       bstrncat(osbuf, TEXT("Enterprise x64 Edition"), maxsiz);
617                    } else {
618                       bstrncat(osbuf, TEXT("Standard x64 Edition"), maxsiz);
619                    }
620                } else {
621                    if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) {
622                       bstrncat(osbuf, TEXT("Compute Cluster Edition"), maxsiz);
623                    } else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
624                       bstrncat(osbuf, TEXT("Datacenter Edition"), maxsiz);
625                    } else if(osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
626                       bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
627                    } else if (osvi.wSuiteMask & VER_SUITE_BLADE) {
628                       bstrncat(osbuf, TEXT("Web Edition"), maxsiz);
629                    } else {
630                       bstrncat(osbuf, TEXT("Standard Edition"), maxsiz);
631                    }
632                }
633             }
634             break;
635          case 1:
636             bstrncat(osbuf, TEXT("Windows XP "), maxsiz);
637             if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
638                bstrncat(osbuf, TEXT("Home Edition"), maxsiz);
639             } else {
640                bstrncat(osbuf, TEXT("Professional"), maxsiz);
641             }
642             break;
643          case 0:
644             bstrncat(osbuf, TEXT("Windows 2000 "), maxsiz);
645             if (osvi.wProductType == VER_NT_WORKSTATION) {
646                bstrncat(osbuf, TEXT("Professional"), maxsiz);
647             } else {
648                if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
649                   bstrncat(osbuf, TEXT("Datacenter Server"), maxsiz);
650                } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
651                   bstrncat(osbuf, TEXT("Advanced Server"), maxsiz);
652                } else {
653                   bstrncat(osbuf, TEXT("Server"), maxsiz);
654                }
655             }
656             break;
657          }
658          break;
659       default:
660          break;
661       }
662 
663       /*
664        * Include service pack (if any) and build number.
665        */
666       if (_tcslen(osvi.szCSDVersion) > 0) {
667           bstrncat(osbuf, TEXT(" ") , maxsiz);
668           bstrncat(osbuf, osvi.szCSDVersion, maxsiz);
669       }
670 
671       char buf[80];
672 
673       snprintf(buf, 80, " (build %d)", (int)osvi.dwBuildNumber);
674       bstrncat(osbuf, buf, maxsiz);
675 
676       if (osvi.dwMajorVersion >= 6) {
677          if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
678             bstrncat(osbuf, TEXT(", 64-bit"), maxsiz);
679          else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
680             bstrncat(osbuf, TEXT(", 32-bit"), maxsiz);
681       }
682 
683       return true;
684    } else {
685       bstrncpy(osbuf, "Unknown Windows version.", maxsiz);
686       return true;
687    }
688 }
689