1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 2001, 2002  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18258945Sroberto/* $Id: strerror.c,v 1.8 2007/06/19 23:47:19 tbox Exp $ */
19258945Sroberto
20258945Sroberto#include <config.h>
21258945Sroberto
22258945Sroberto#include <stdio.h>
23258945Sroberto#include <string.h>
24258945Sroberto#include <winsock2.h>
25258945Sroberto
26258945Sroberto#include <isc/mutex.h>
27258945Sroberto#include <isc/once.h>
28258945Sroberto#include <isc/print.h>
29258945Sroberto#include <isc/strerror.h>
30258945Sroberto#include <isc/util.h>
31258945Sroberto
32258945Sroberto/*
33258945Sroberto * Forward declarations
34258945Sroberto */
35258945Sroberto
36258945Srobertochar *
37258945SrobertoFormatError(int error);
38258945Sroberto
39258945Srobertochar *
40258945SrobertoGetWSAErrorMessage(int errval);
41258945Sroberto
42258945Srobertochar *
43258945SrobertoNTstrerror(int err, BOOL *bfreebuf);
44258945Sroberto
45258945Sroberto/*
46258945Sroberto * We need to do this this way for profiled locks.
47258945Sroberto */
48258945Sroberto
49258945Srobertostatic isc_mutex_t isc_strerror_lock;
50258945Srobertostatic void init_lock(void) {
51258945Sroberto	RUNTIME_CHECK(isc_mutex_init(&isc_strerror_lock) == ISC_R_SUCCESS);
52258945Sroberto}
53258945Sroberto
54258945Sroberto/*
55258945Sroberto * This routine needs to free up any buffer allocated by FormatMessage
56258945Sroberto * if that routine gets used.
57258945Sroberto */
58258945Sroberto
59258945Srobertovoid
60258945Srobertoisc__strerror(int num, char *buf, size_t size) {
61258945Sroberto	char *msg;
62258945Sroberto	BOOL freebuf;
63258945Sroberto	unsigned int unum = num;
64258945Sroberto	static isc_once_t once = ISC_ONCE_INIT;
65258945Sroberto
66258945Sroberto	REQUIRE(buf != NULL);
67258945Sroberto
68258945Sroberto	RUNTIME_CHECK(isc_once_do(&once, init_lock) == ISC_R_SUCCESS);
69258945Sroberto
70258945Sroberto	LOCK(&isc_strerror_lock);
71258945Sroberto	freebuf = FALSE;
72258945Sroberto	msg = NTstrerror(num, &freebuf);
73258945Sroberto	if (msg != NULL)
74258945Sroberto		snprintf(buf, size, "%s", msg);
75258945Sroberto	else
76258945Sroberto		snprintf(buf, size, "Unknown error: %u", unum);
77258945Sroberto	if(freebuf && msg != NULL) {
78258945Sroberto		LocalFree(msg);
79258945Sroberto	}
80258945Sroberto	UNLOCK(&isc_strerror_lock);
81258945Sroberto}
82258945Sroberto
83258945Sroberto/*
84258945Sroberto * Note this will cause a memory leak unless the memory allocated here
85258945Sroberto * is freed by calling LocalFree.  isc__strerror does this before unlocking.
86258945Sroberto * This only gets called if there is a system type of error and will likely
87258945Sroberto * be an unusual event.
88258945Sroberto */
89258945Srobertochar *
90258945SrobertoFormatError(int error) {
91258945Sroberto	LPVOID lpMsgBuf = NULL;
92258945Sroberto	FormatMessage(
93258945Sroberto		FORMAT_MESSAGE_ALLOCATE_BUFFER |
94258945Sroberto		FORMAT_MESSAGE_FROM_SYSTEM |
95258945Sroberto		FORMAT_MESSAGE_IGNORE_INSERTS,
96258945Sroberto		NULL,
97258945Sroberto		error,
98258945Sroberto		/* Default language */
99258945Sroberto		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
100258945Sroberto		(LPTSTR) &lpMsgBuf,
101258945Sroberto		0,
102258945Sroberto		NULL);
103258945Sroberto
104258945Sroberto	return (lpMsgBuf);
105258945Sroberto}
106258945Sroberto
107258945Sroberto/*
108258945Sroberto * This routine checks the error value and calls the WSA Windows Sockets
109258945Sroberto * Error message function GetWSAErrorMessage below if it's within that range
110258945Sroberto * since those messages are not available in the system error messages.
111258945Sroberto */
112258945Srobertochar *
113258945SrobertoNTstrerror(int err, BOOL *bfreebuf) {
114258945Sroberto	char *retmsg = NULL;
115258945Sroberto
116258945Sroberto	/* Copy the error value first in case of other errors */
117258945Sroberto	DWORD errval = err;
118258945Sroberto
119258945Sroberto	*bfreebuf = FALSE;
120258945Sroberto
121258945Sroberto	/* Get the Winsock2 error messages */
122258945Sroberto	if (errval >= WSABASEERR && errval <= (WSABASEERR + 1015)) {
123258945Sroberto		retmsg = GetWSAErrorMessage(errval);
124258945Sroberto		if (retmsg != NULL)
125258945Sroberto			return (retmsg);
126258945Sroberto	}
127258945Sroberto	/*
128258945Sroberto	 * If it's not one of the standard Unix error codes,
129258945Sroberto	 * try a system error message
130258945Sroberto	 */
131258945Sroberto	if (errval > (DWORD) _sys_nerr) {
132258945Sroberto		*bfreebuf = TRUE;
133258945Sroberto		return (FormatError(errval));
134258945Sroberto	} else {
135258945Sroberto		return (strerror(errval));
136258945Sroberto	}
137258945Sroberto}
138258945Sroberto
139258945Sroberto/*
140258945Sroberto * This is a replacement for perror
141258945Sroberto */
142258945Srobertovoid __cdecl
143258945SrobertoNTperror(char *errmsg) {
144258945Sroberto	/* Copy the error value first in case of other errors */
145258945Sroberto	int errval = errno;
146258945Sroberto	BOOL bfreebuf = FALSE;
147258945Sroberto	char *msg;
148258945Sroberto
149258945Sroberto	msg = NTstrerror(errval, &bfreebuf);
150258945Sroberto	fprintf(stderr, "%s: %s\n", errmsg, msg);
151258945Sroberto	if(bfreebuf == TRUE) {
152258945Sroberto		LocalFree(msg);
153258945Sroberto	}
154258945Sroberto
155258945Sroberto}
156258945Sroberto
157258945Sroberto/*
158258945Sroberto * Return the error string related to Winsock2 errors.
159258945Sroberto * This function is necessary since FormatMessage knows nothing about them
160258945Sroberto * and there is no function to get them.
161258945Sroberto */
162258945Srobertochar *
163258945SrobertoGetWSAErrorMessage(int errval) {
164258945Sroberto	char *msg;
165258945Sroberto
166258945Sroberto	switch (errval) {
167258945Sroberto
168258945Sroberto	case WSAEINTR:
169258945Sroberto		msg = "Interrupted system call";
170258945Sroberto		break;
171258945Sroberto
172258945Sroberto	case WSAEBADF:
173258945Sroberto		msg = "Bad file number";
174258945Sroberto		break;
175258945Sroberto
176258945Sroberto	case WSAEACCES:
177258945Sroberto		msg = "Permission denied";
178258945Sroberto		break;
179258945Sroberto
180258945Sroberto	case WSAEFAULT:
181258945Sroberto		msg = "Bad address";
182258945Sroberto		break;
183258945Sroberto
184258945Sroberto	case WSAEINVAL:
185258945Sroberto		msg = "Invalid argument";
186258945Sroberto		break;
187258945Sroberto
188258945Sroberto	case WSAEMFILE:
189258945Sroberto		msg = "Too many open sockets";
190258945Sroberto		break;
191258945Sroberto
192258945Sroberto	case WSAEWOULDBLOCK:
193258945Sroberto		msg = "Operation would block";
194258945Sroberto		break;
195258945Sroberto
196258945Sroberto	case WSAEINPROGRESS:
197258945Sroberto		msg = "Operation now in progress";
198258945Sroberto		break;
199258945Sroberto
200258945Sroberto	case WSAEALREADY:
201258945Sroberto		msg = "Operation already in progress";
202258945Sroberto		break;
203258945Sroberto
204258945Sroberto	case WSAENOTSOCK:
205258945Sroberto		msg = "Socket operation on non-socket";
206258945Sroberto		break;
207258945Sroberto
208258945Sroberto	case WSAEDESTADDRREQ:
209258945Sroberto		msg = "Destination address required";
210258945Sroberto		break;
211258945Sroberto
212258945Sroberto	case WSAEMSGSIZE:
213258945Sroberto		msg = "Message too long";
214258945Sroberto		break;
215258945Sroberto
216258945Sroberto	case WSAEPROTOTYPE:
217258945Sroberto		msg = "Protocol wrong type for socket";
218258945Sroberto		break;
219258945Sroberto
220258945Sroberto	case WSAENOPROTOOPT:
221258945Sroberto		msg = "Bad protocol option";
222258945Sroberto		break;
223258945Sroberto
224258945Sroberto	case WSAEPROTONOSUPPORT:
225258945Sroberto		msg = "Protocol not supported";
226258945Sroberto		break;
227258945Sroberto
228258945Sroberto	case WSAESOCKTNOSUPPORT:
229258945Sroberto		msg = "Socket type not supported";
230258945Sroberto		break;
231258945Sroberto
232258945Sroberto	case WSAEOPNOTSUPP:
233258945Sroberto		msg = "Operation not supported on socket";
234258945Sroberto		break;
235258945Sroberto
236258945Sroberto	case WSAEPFNOSUPPORT:
237258945Sroberto		msg = "Protocol family not supported";
238258945Sroberto		break;
239258945Sroberto
240258945Sroberto	case WSAEAFNOSUPPORT:
241258945Sroberto		msg = "Address family not supported";
242258945Sroberto		break;
243258945Sroberto
244258945Sroberto	case WSAEADDRINUSE:
245258945Sroberto		msg = "Address already in use";
246258945Sroberto		break;
247258945Sroberto
248258945Sroberto	case WSAEADDRNOTAVAIL:
249258945Sroberto		msg = "Can't assign requested address";
250258945Sroberto		break;
251258945Sroberto
252258945Sroberto	case WSAENETDOWN:
253258945Sroberto		msg = "Network is down";
254258945Sroberto		break;
255258945Sroberto
256258945Sroberto	case WSAENETUNREACH:
257258945Sroberto		msg = "Network is unreachable";
258258945Sroberto		break;
259258945Sroberto
260258945Sroberto	case WSAENETRESET:
261258945Sroberto		msg = "Net connection reset";
262258945Sroberto		break;
263258945Sroberto
264258945Sroberto	case WSAECONNABORTED:
265258945Sroberto		msg = "Software caused connection abort";
266258945Sroberto		break;
267258945Sroberto
268258945Sroberto	case WSAECONNRESET:
269258945Sroberto		msg = "Connection reset by peer";
270258945Sroberto		break;
271258945Sroberto
272258945Sroberto	case WSAENOBUFS:
273258945Sroberto		msg = "No buffer space available";
274258945Sroberto		break;
275258945Sroberto
276258945Sroberto	case WSAEISCONN:
277258945Sroberto		msg = "Socket is already connected";
278258945Sroberto		break;
279258945Sroberto
280258945Sroberto	case WSAENOTCONN:
281258945Sroberto		msg = "Socket is not connected";
282258945Sroberto		break;
283258945Sroberto
284258945Sroberto	case WSAESHUTDOWN:
285258945Sroberto		msg = "Can't send after socket shutdown";
286258945Sroberto		break;
287258945Sroberto
288258945Sroberto	case WSAETOOMANYREFS:
289258945Sroberto		msg = "Too many references: can't splice";
290258945Sroberto		break;
291258945Sroberto
292258945Sroberto	case WSAETIMEDOUT:
293258945Sroberto		msg = "Connection timed out";
294258945Sroberto		break;
295258945Sroberto
296258945Sroberto	case WSAECONNREFUSED:
297258945Sroberto		msg = "Connection refused";
298258945Sroberto		break;
299258945Sroberto
300258945Sroberto	case WSAELOOP:
301258945Sroberto		msg = "Too many levels of symbolic links";
302258945Sroberto		break;
303258945Sroberto
304258945Sroberto	case WSAENAMETOOLONG:
305258945Sroberto		msg = "File name too long";
306258945Sroberto		break;
307258945Sroberto
308258945Sroberto	case WSAEHOSTDOWN:
309258945Sroberto		msg = "Host is down";
310258945Sroberto		break;
311258945Sroberto
312258945Sroberto	case WSAEHOSTUNREACH:
313258945Sroberto		msg = "No route to host";
314258945Sroberto		break;
315258945Sroberto
316258945Sroberto	case WSAENOTEMPTY:
317258945Sroberto		msg = "Directory not empty";
318258945Sroberto		break;
319258945Sroberto
320258945Sroberto	case WSAEPROCLIM:
321258945Sroberto		msg = "Too many processes";
322258945Sroberto		break;
323258945Sroberto
324258945Sroberto	case WSAEUSERS:
325258945Sroberto		msg = "Too many users";
326258945Sroberto		break;
327258945Sroberto
328258945Sroberto	case WSAEDQUOT:
329258945Sroberto		msg = "Disc quota exceeded";
330258945Sroberto		break;
331258945Sroberto
332258945Sroberto	case WSAESTALE:
333258945Sroberto		msg = "Stale NFS file handle";
334258945Sroberto		break;
335258945Sroberto
336258945Sroberto	case WSAEREMOTE:
337258945Sroberto		msg = "Too many levels of remote in path";
338258945Sroberto		break;
339258945Sroberto
340258945Sroberto	case WSASYSNOTREADY:
341258945Sroberto		msg = "Network system is unavailable";
342258945Sroberto		break;
343258945Sroberto
344258945Sroberto	case WSAVERNOTSUPPORTED:
345258945Sroberto		msg = "Winsock version out of range";
346258945Sroberto		break;
347258945Sroberto
348258945Sroberto	case WSANOTINITIALISED:
349258945Sroberto		msg = "WSAStartup not yet called";
350258945Sroberto		break;
351258945Sroberto
352258945Sroberto	case WSAEDISCON:
353258945Sroberto		msg = "Graceful shutdown in progress";
354258945Sroberto		break;
355258945Sroberto/*
356258945Sroberto	case WSAHOST_NOT_FOUND:
357258945Sroberto		msg = "Host not found";
358258945Sroberto		break;
359258945Sroberto
360258945Sroberto	case WSANO_DATA:
361258945Sroberto		msg = "No host data of that type was found";
362258945Sroberto		break;
363258945Sroberto*/
364258945Sroberto	default:
365258945Sroberto		msg = NULL;
366258945Sroberto		break;
367258945Sroberto	}
368258945Sroberto	return (msg);
369258945Sroberto}
370258945Sroberto
371258945Sroberto/*
372258945Sroberto * These error messages are more informative about CryptAPI Errors than the
373258945Sroberto * standard error messages
374258945Sroberto */
375258945Sroberto
376258945Srobertochar *
377258945SrobertoGetCryptErrorMessage(int errval) {
378258945Sroberto	char *msg;
379258945Sroberto
380258945Sroberto	switch (errval) {
381258945Sroberto
382258945Sroberto	case NTE_BAD_FLAGS:
383258945Sroberto		msg = "The dwFlags parameter has an illegal value.";
384258945Sroberto		break;
385258945Sroberto	case NTE_BAD_KEYSET:
386258945Sroberto		msg = "The Registry entry for the key container "
387258945Sroberto			"could not be opened and may not exist.";
388258945Sroberto		break;
389258945Sroberto	case NTE_BAD_KEYSET_PARAM:
390258945Sroberto		msg = "The pszContainer or pszProvider parameter "
391258945Sroberto			"is set to an illegal value.";
392258945Sroberto		break;
393258945Sroberto	case NTE_BAD_PROV_TYPE:
394258945Sroberto		msg = "The value of the dwProvType parameter is out "
395258945Sroberto			"of range. All provider types must be from "
396258945Sroberto			"1 to 999, inclusive.";
397258945Sroberto		break;
398258945Sroberto	case NTE_BAD_SIGNATURE:
399258945Sroberto		msg = "The provider DLL signature did not verify "
400258945Sroberto			"correctly. Either the DLL or the digital "
401258945Sroberto			"signature has been tampered with.";
402258945Sroberto		break;
403258945Sroberto	case NTE_EXISTS:
404258945Sroberto		msg = "The dwFlags parameter is CRYPT_NEWKEYSET, but the key"
405258945Sroberto		      " container already exists.";
406258945Sroberto		break;
407258945Sroberto	case NTE_KEYSET_ENTRY_BAD:
408258945Sroberto		msg = "The Registry entry for the pszContainer key container "
409258945Sroberto		      "was found (in the HKEY_CURRENT_USER window), but is "
410258945Sroberto		      "corrupt. See the section System Administration for "
411258945Sroberto		      " etails about CryptoAPI's Registry usage.";
412258945Sroberto		break;
413258945Sroberto	case NTE_KEYSET_NOT_DEF:
414258945Sroberto		msg = "No Registry entry exists in the HKEY_CURRENT_USER "
415258945Sroberto			"window for the key container specified by "
416258945Sroberto			"pszContainer.";
417258945Sroberto		break;
418258945Sroberto	case NTE_NO_MEMORY:
419258945Sroberto		msg = "The CSP ran out of memory during the operation.";
420258945Sroberto		break;
421258945Sroberto	case NTE_PROV_DLL_NOT_FOUND:
422258945Sroberto		msg = "The provider DLL file does not exist or is not on the "
423258945Sroberto		      "current path.";
424258945Sroberto		break;
425258945Sroberto	case NTE_PROV_TYPE_ENTRY_BAD:
426258945Sroberto		msg = "The Registry entry for the provider type specified by "
427258945Sroberto		      "dwProvType is corrupt. This error may relate to "
428258945Sroberto		      "either the user default CSP list or the machine "
429258945Sroberto		      "default CSP list. See the section System "
430258945Sroberto		      "Administration for details about CryptoAPI's "
431258945Sroberto		      "Registry usage.";
432258945Sroberto		break;
433258945Sroberto	case NTE_PROV_TYPE_NO_MATCH:
434258945Sroberto		msg = "The provider type specified by dwProvType does not "
435258945Sroberto		      "match the provider type found in the Registry. Note "
436258945Sroberto		      "that this error can only occur when pszProvider "
437258945Sroberto		      "specifies an actual CSP name.";
438258945Sroberto		break;
439258945Sroberto	case NTE_PROV_TYPE_NOT_DEF:
440258945Sroberto		msg = "No Registry entry exists for the provider type "
441258945Sroberto		      "specified by dwProvType.";
442258945Sroberto		break;
443258945Sroberto	case NTE_PROVIDER_DLL_FAIL:
444258945Sroberto		msg = "The provider DLL file could not be loaded, and "
445258945Sroberto		      "may not exist. If it exists, then the file is "
446258945Sroberto		      "not a valid DLL.";
447258945Sroberto		break;
448258945Sroberto	case NTE_SIGNATURE_FILE_BAD:
449258945Sroberto		msg = "An error occurred while loading the DLL file image, "
450258945Sroberto		      "prior to verifying its signature.";
451258945Sroberto		break;
452258945Sroberto
453258945Sroberto	default:
454258945Sroberto		msg = NULL;
455258945Sroberto		break;
456258945Sroberto	}
457258945Sroberto	return msg;
458258945Sroberto}
459258945Sroberto
460