1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* MS Windows implementation of gp_getenv, and gp_serialnumber */
18 
19 #include "windows_.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>		/* for getenv */
23 #include <string.h>
24 #include "gscdefs.h"		/* for gs_productfamily and gs_revision and gs_serialnumber */
25 
26 #if defined(__WIN32__) && !defined(METRO)
27 /*
28  * Get a named registry value.
29  * Key = hkeyroot\\key, named value = name.
30  * name, ptr, plen and return values are the same as in gp_getenv();
31  */
32 int
gp_getenv_registry(HKEY hkeyroot,const wchar_t * key,const char * name,char * ptr,int * plen)33 gp_getenv_registry(HKEY hkeyroot, const wchar_t *key, const char *name,
34     char *ptr, int *plen)
35 {
36     HKEY hkey;
37     DWORD cbData, keytype;
38     wchar_t w;
39     LONG rc;
40     wchar_t *wptr;
41     wchar_t *wp = NULL;
42     wchar_t *wname;
43     int l = -1;
44 
45     if (*plen) {
46         wp = malloc((*plen)*sizeof(wchar_t));
47         if (wp == NULL)
48             return 1;
49     }
50     wptr = wp;
51 
52     wname = malloc(utf8_to_wchar(NULL, name)*sizeof(wchar_t));
53     if (wname == NULL) {
54         if (wp)
55             free(wp);
56         return 1;
57     }
58     utf8_to_wchar(wname, name);
59 
60     if (RegOpenKeyExW(hkeyroot, key, 0, KEY_READ, &hkey) != ERROR_SUCCESS) {
61         free(wname);
62         if (wp)
63             free(wp);
64         return 1; /* Not found */
65     }
66     keytype = REG_SZ;
67     cbData = (*plen) * sizeof(wchar_t);
68     if (wptr == NULL)                   /* Registry API won't return */
69         wptr = &w;	                /* ERROR_MORE_DATA if ptr is NULL */
70     rc = RegQueryValueExW(hkey, wname, 0, &keytype, (BYTE *)wptr, &cbData);
71     RegCloseKey(hkey);
72     /* Process string keys, ignore keys that are not strings */
73     if (keytype == REG_SZ) {
74         switch (rc) {
75             case ERROR_SUCCESS:
76                 if (wp) {
77                     l = wchar_to_utf8(NULL, wp);
78                     if (l <= *plen) {
79                         *plen = wchar_to_utf8(ptr, wp);
80                         free(wp);
81                         free(wname);
82                         return 0;       /* found environment variable and copied it */
83                     } else;             /* buffer too small, so fall through */
84                 }                       /* caller only asked for the size, so fall through */
85             case ERROR_MORE_DATA:
86                 /* buffer wasn't large enough or caller only asked for the size */
87                 if (l >= 0L) {
88                     /* buffer size already computed above */
89                     *plen = l;
90                 } else {
91                     /* If we're probing for the size, then worst case, it can
92                      * take 3 bytes out for every 2 bytes in. */
93                     *plen = (cbData*3+1)/2;
94                 }
95                 if (wp)
96                     free(wp);
97                 free(wname);
98                 return -1;              /* found environment variable, but buffer too small */
99             default:
100                 break;
101         }
102     }
103     if (wp)
104         free(wp);
105     free(wname);
106     return 1;                           /* environment variable does not exist */
107 }
108 #endif    /* ifdef __WIN32__ */
109 
110 /* ------ Environment variables ------ */
111 
112 /* Get the value of an environment variable.  See gp.h for details. */
113 int
gp_getenv(const char * name,char * ptr,int * plen)114 gp_getenv(const char *name, char *ptr, int *plen)
115 {
116     wchar_t *wname;
117     wchar_t *str;
118 
119     wname = malloc(utf8_to_wchar(NULL, name)*sizeof(wchar_t));
120     if (wname == NULL) {
121         return -1;
122     }
123     utf8_to_wchar(wname, name);
124 
125     str = _wgetenv(wname);
126 
127     free(wname);
128 
129     if (str) {
130         /* wchar_to_utf8 returns INCLUDING terminator */
131         int len = wchar_to_utf8(NULL, str);
132 
133         if (len <= *plen) {
134             /* string fits */
135             *plen = wchar_to_utf8(ptr, str);
136             return 0;
137         }
138         /* string doesn't fit */
139         *plen = len;
140         return -1;
141     }
142     /* environment variable was not found */
143 
144 #if defined(__WIN32__) && !defined(METRO)
145     {
146         /* If using Win32, look in the registry for a value with
147          * the given name.  The registry value will be under the key
148          * HKEY_CURRENT_USER\Software\GPL Ghostscript\N.NN
149          * or if that fails under the key
150          * HKEY_LOCAL_MACHINE\Software\GPL Ghostscript\N.NN
151          * where "GPL Ghostscript" is actually gs_productfamily
152          * and N.NN is obtained from gs_revision.
153          */
154         DWORD version = GetVersion();
155 
156         if (!(((HIWORD(version) & 0x8000) != 0)
157               && ((HIWORD(version) & 0x4000) == 0))) {
158             /* not Win32s */
159             int code;
160             wchar_t key[256];
161             wchar_t dotversion[16];
162 
163             wsprintfW(dotversion, L"%d.%02d", (int)(gs_revision / 100),
164                       (int)(gs_revision % 100));
165             wsprintfW(key, L"Software\\%hs\\%s", gs_productfamily, dotversion);
166             code = gp_getenv_registry(HKEY_CURRENT_USER, key, name, ptr, plen);
167             if ( code <= 0 )
168                 return code;	/* found it */
169 
170             code = gp_getenv_registry(HKEY_LOCAL_MACHINE, key, name, ptr, plen);
171             if ( code <= 0 )
172                 return code;	/* found it */
173         }
174     }
175 #endif
176 
177     /* nothing found at all */
178 
179     if (*plen > 0)
180         *ptr = 0;
181     *plen = 1;
182     return 1;
183 }
184 
185 /* If we aren't on WIN32, We don't have a good way to get a serial */
186 /* number here, so just return what we always used to */
187 int
gp_serialnumber(void)188 gp_serialnumber(void)
189 {
190 #if defined(__WIN32__) && !defined(METRO)
191 #define SERIALNUMBER_BUFSIZE 512
192     byte buf[SERIALNUMBER_BUFSIZE];
193     int buflen = SERIALNUMBER_BUFSIZE;
194     int code, i;
195     wchar_t key[256];
196 
197     wsprintfW(key, L"Software\\Microsoft\\MSLicensing\\HardwareID");
198     code = gp_getenv_registry(HKEY_LOCAL_MACHINE, key, "ClientHWID", (char *)buf, &buflen);
199     if ( code != 0 )
200         return (int)(gs_serialnumber); 	/* error - just return the default */
201 
202     /* now turn the buffer into a 31-bit (avoid negative values) integer */
203     for (i=0, code=0; i<buflen; i++)
204         code += code + (buf[i] ^ i) + (code >> 31);      /* a cheap checksum */
205 
206     return code & 0x7fffffff;    /* strip the high bit */
207 
208 #endif    /* __WIN32__ */
209 
210     return (int)(gs_serialnumber);
211 }
212