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