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