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