1/*
2 * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001, 2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: strerror.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */
19
20#include <config.h>
21
22#include <stdio.h>
23#include <string.h>
24#include <winsock2.h>
25
26#include <isc/mutex.h>
27#include <isc/once.h>
28#include <isc/print.h>
29#include <isc/strerror.h>
30#include <isc/util.h>
31
32/*
33 * Forward declarations
34 */
35
36char *
37FormatError(int error);
38
39char *
40GetWSAErrorMessage(int errval);
41
42char *
43NTstrerror(int err, BOOL *bfreebuf);
44
45/*
46 * We need to do this this way for profiled locks.
47 */
48
49static isc_mutex_t isc_strerror_lock;
50static void init_lock(void) {
51	RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
52}
53
54/*
55 * This routine needs to free up any buffer allocated by FormatMessage
56 * if that routine gets used.
57 */
58
59void
60isc__strerror(int num, char *buf, size_t size) {
61	char *msg;
62	BOOL freebuf;
63	unsigned int unum = num;
64	static isc_once_t once = ISC_ONCE_INIT;
65
66	REQUIRE(buf != NULL);
67
68	RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
69
70	LOCK(&isc_strerror_lock);
71	freebuf = FALSE;
72	msg = NTstrerror(num, &freebuf);
73	if (msg != NULL)
74		snprintf(buf, size, "%s", msg);
75	else
76		snprintf(buf, size, "Unknown error: %u", unum);
77	if(freebuf && msg != NULL) {
78		LocalFree(msg);
79	}
80	UNLOCK(&isc_strerror_lock);
81}
82
83/*
84 * Note this will cause a memory leak unless the memory allocated here
85 * is freed by calling LocalFree.  isc__strerror does this before unlocking.
86 * This only gets called if there is a system type of error and will likely
87 * be an unusual event.
88 */
89char *
90FormatError(int error) {
91	LPVOID lpMsgBuf = NULL;
92	FormatMessage(
93		FORMAT_MESSAGE_ALLOCATE_BUFFER |
94		FORMAT_MESSAGE_FROM_SYSTEM |
95		FORMAT_MESSAGE_IGNORE_INSERTS,
96		NULL,
97		error,
98		/* Default language */
99		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
100		(LPTSTR) &lpMsgBuf,
101		0,
102		NULL);
103
104	return (lpMsgBuf);
105}
106
107/*
108 * This routine checks the error value and calls the WSA Windows Sockets
109 * Error message function GetWSAErrorMessage below if it's within that range
110 * since those messages are not available in the system error messages.
111 */
112char *
113NTstrerror(int err, BOOL *bfreebuf) {
114	char *retmsg = NULL;
115
116	/* Copy the error value first in case of other errors */
117	DWORD errval = err;
118
119	*bfreebuf = FALSE;
120
121	/* Get the Winsock2 error messages */
122	if (errval >= WSABASEERR && errval <= (WSABASEERR + 1015)) {
123		retmsg = GetWSAErrorMessage(errval);
124		if (retmsg != NULL)
125			return (retmsg);
126	}
127	/*
128	 * If it's not one of the standard Unix error codes,
129	 * try a system error message
130	 */
131	if (errval > (DWORD) _sys_nerr) {
132		*bfreebuf = TRUE;
133		return (FormatError(errval));
134	} else {
135		return (strerror(errval));
136	}
137}
138
139/*
140 * This is a replacement for perror
141 */
142void __cdecl
143NTperror(char *errmsg) {
144	/* Copy the error value first in case of other errors */
145	int errval = errno;
146	BOOL bfreebuf = FALSE;
147	char *msg;
148
149	msg = NTstrerror(errval, &bfreebuf);
150	fprintf(stderr, "%s: %s\n", errmsg, msg);
151	if(bfreebuf == TRUE) {
152		LocalFree(msg);
153	}
154
155}
156
157/*
158 * Return the error string related to Winsock2 errors.
159 * This function is necessary since FormatMessage knows nothing about them
160 * and there is no function to get them.
161 */
162char *
163GetWSAErrorMessage(int errval) {
164	char *msg;
165
166	switch (errval) {
167
168	case WSAEINTR:
169		msg = "Interrupted system call";
170		break;
171
172	case WSAEBADF:
173		msg = "Bad file number";
174		break;
175
176	case WSAEACCES:
177		msg = "Permission denied";
178		break;
179
180	case WSAEFAULT:
181		msg = "Bad address";
182		break;
183
184	case WSAEINVAL:
185		msg = "Invalid argument";
186		break;
187
188	case WSAEMFILE:
189		msg = "Too many open sockets";
190		break;
191
192	case WSAEWOULDBLOCK:
193		msg = "Operation would block";
194		break;
195
196	case WSAEINPROGRESS:
197		msg = "Operation now in progress";
198		break;
199
200	case WSAEALREADY:
201		msg = "Operation already in progress";
202		break;
203
204	case WSAENOTSOCK:
205		msg = "Socket operation on non-socket";
206		break;
207
208	case WSAEDESTADDRREQ:
209		msg = "Destination address required";
210		break;
211
212	case WSAEMSGSIZE:
213		msg = "Message too long";
214		break;
215
216	case WSAEPROTOTYPE:
217		msg = "Protocol wrong type for socket";
218		break;
219
220	case WSAENOPROTOOPT:
221		msg = "Bad protocol option";
222		break;
223
224	case WSAEPROTONOSUPPORT:
225		msg = "Protocol not supported";
226		break;
227
228	case WSAESOCKTNOSUPPORT:
229		msg = "Socket type not supported";
230		break;
231
232	case WSAEOPNOTSUPP:
233		msg = "Operation not supported on socket";
234		break;
235
236	case WSAEPFNOSUPPORT:
237		msg = "Protocol family not supported";
238		break;
239
240	case WSAEAFNOSUPPORT:
241		msg = "Address family not supported";
242		break;
243
244	case WSAEADDRINUSE:
245		msg = "Address already in use";
246		break;
247
248	case WSAEADDRNOTAVAIL:
249		msg = "Can't assign requested address";
250		break;
251
252	case WSAENETDOWN:
253		msg = "Network is down";
254		break;
255
256	case WSAENETUNREACH:
257		msg = "Network is unreachable";
258		break;
259
260	case WSAENETRESET:
261		msg = "Net connection reset";
262		break;
263
264	case WSAECONNABORTED:
265		msg = "Software caused connection abort";
266		break;
267
268	case WSAECONNRESET:
269		msg = "Connection reset by peer";
270		break;
271
272	case WSAENOBUFS:
273		msg = "No buffer space available";
274		break;
275
276	case WSAEISCONN:
277		msg = "Socket is already connected";
278		break;
279
280	case WSAENOTCONN:
281		msg = "Socket is not connected";
282		break;
283
284	case WSAESHUTDOWN:
285		msg = "Can't send after socket shutdown";
286		break;
287
288	case WSAETOOMANYREFS:
289		msg = "Too many references: can't splice";
290		break;
291
292	case WSAETIMEDOUT:
293		msg = "Connection timed out";
294		break;
295
296	case WSAECONNREFUSED:
297		msg = "Connection refused";
298		break;
299
300	case WSAELOOP:
301		msg = "Too many levels of symbolic links";
302		break;
303
304	case WSAENAMETOOLONG:
305		msg = "File name too long";
306		break;
307
308	case WSAEHOSTDOWN:
309		msg = "Host is down";
310		break;
311
312	case WSAEHOSTUNREACH:
313		msg = "No route to host";
314		break;
315
316	case WSAENOTEMPTY:
317		msg = "Directory not empty";
318		break;
319
320	case WSAEPROCLIM:
321		msg = "Too many processes";
322		break;
323
324	case WSAEUSERS:
325		msg = "Too many users";
326		break;
327
328	case WSAEDQUOT:
329		msg = "Disc quota exceeded";
330		break;
331
332	case WSAESTALE:
333		msg = "Stale NFS file handle";
334		break;
335
336	case WSAEREMOTE:
337		msg = "Too many levels of remote in path";
338		break;
339
340	case WSASYSNOTREADY:
341		msg = "Network system is unavailable";
342		break;
343
344	case WSAVERNOTSUPPORTED:
345		msg = "Winsock version out of range";
346		break;
347
348	case WSANOTINITIALISED:
349		msg = "WSAStartup not yet called";
350		break;
351
352	case WSAEDISCON:
353		msg = "Graceful shutdown in progress";
354		break;
355/*
356	case WSAHOST_NOT_FOUND:
357		msg = "Host not found";
358		break;
359
360	case WSANO_DATA:
361		msg = "No host data of that type was found";
362		break;
363*/
364	default:
365		msg = NULL;
366		break;
367	}
368	return (msg);
369}
370
371/*
372 * These error messages are more informative about CryptAPI Errors than the
373 * standard error messages
374 */
375
376char *
377GetCryptErrorMessage(int errval) {
378	char *msg;
379
380	switch (errval) {
381
382	case NTE_BAD_FLAGS:
383		msg = "The dwFlags parameter has an illegal value.";
384		break;
385	case NTE_BAD_KEYSET:
386		msg = "The Registry entry for the key container "
387			"could not be opened and may not exist.";
388		break;
389	case NTE_BAD_KEYSET_PARAM:
390		msg = "The pszContainer or pszProvider parameter "
391			"is set to an illegal value.";
392		break;
393	case NTE_BAD_PROV_TYPE:
394		msg = "The value of the dwProvType parameter is out "
395			"of range. All provider types must be from "
396			"1 to 999, inclusive.";
397		break;
398	case NTE_BAD_SIGNATURE:
399		msg = "The provider DLL signature did not verify "
400			"correctly. Either the DLL or the digital "
401			"signature has been tampered with.";
402		break;
403	case NTE_EXISTS:
404		msg = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key"
405		      " container already exists.";
406		break;
407	case NTE_KEYSET_ENTRY_BAD:
408		msg = "The Registry entry for the pszContainer key container "
409		      "was found (in the HKEY_CURRENT_USER window), but is "
410		      "corrupt. See the section System Administration for "
411		      " etails about CryptoAPI's Registry usage.";
412		break;
413	case NTE_KEYSET_NOT_DEF:
414		msg = "No Registry entry exists in the HKEY_CURRENT_USER "
415			"window for the key container specified by "
416			"pszContainer.";
417		break;
418	case NTE_NO_MEMORY:
419		msg = "The CSP ran out of memory during the operation.";
420		break;
421	case NTE_PROV_DLL_NOT_FOUND:
422		msg = "The provider DLL file does not exist or is not on the "
423		      "current path.";
424		break;
425	case NTE_PROV_TYPE_ENTRY_BAD:
426		msg = "The Registry entry for the provider type specified by "
427		      "dwProvType is corrupt. This error may relate to "
428		      "either the user default CSP list or the machine "
429		      "default CSP list. See the section System "
430		      "Administration for details about CryptoAPI's "
431		      "Registry usage.";
432		break;
433	case NTE_PROV_TYPE_NO_MATCH:
434		msg = "The provider type specified by dwProvType does not "
435		      "match the provider type found in the Registry. Note "
436		      "that this error can only occur when pszProvider "
437		      "specifies an actual CSP name.";
438		break;
439	case NTE_PROV_TYPE_NOT_DEF:
440		msg = "No Registry entry exists for the provider type "
441		      "specified by dwProvType.";
442		break;
443	case NTE_PROVIDER_DLL_FAIL:
444		msg = "The provider DLL file could not be loaded, and "
445		      "may not exist. If it exists, then the file is "
446		      "not a valid DLL.";
447		break;
448	case NTE_SIGNATURE_FILE_BAD:
449		msg = "An error occurred while loading the DLL file image, "
450		      "prior to verifying its signature.";
451		break;
452
453	default:
454		msg = NULL;
455		break;
456	}
457	return msg;
458}
459
460