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