1/*	$NetBSD: clnt_perror.c,v 1.28 2008/04/25 17:44:44 christos Exp $	*/
2
3/*
4 * Copyright (c) 2010, Oracle America, Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above
13 *       copyright notice, this list of conditions and the following
14 *       disclaimer in the documentation and/or other materials
15 *       provided with the distribution.
16 *     * Neither the name of the "Oracle America, Inc." nor the names of its
17 *       contributors may be used to endorse or promote products derived
18 *       from this software without specific prior written permission.
19 *
20 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35#if defined(LIBC_SCCS) && !defined(lint)
36#if 0
37static char *sccsid = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
38static char *sccsid = "@(#)clnt_perror.c	2.1 88/07/29 4.0 RPCSRC";
39#else
40__RCSID("$NetBSD: clnt_perror.c,v 1.28 2008/04/25 17:44:44 christos Exp $");
41#endif
42#endif
43
44/*
45 * clnt_perror.c
46 *
47 * Copyright (C) 1984, Sun Microsystems, Inc.
48 *
49 */
50#include "namespace.h"
51
52#include <assert.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56
57#include <rpc/rpc.h>
58#include <rpc/types.h>
59#include <rpc/auth.h>
60#include <rpc/clnt.h>
61
62#ifdef __weak_alias
63__weak_alias(clnt_pcreateerror,_clnt_pcreateerror)
64__weak_alias(clnt_perrno,_clnt_perrno)
65__weak_alias(clnt_perror,_clnt_perror)
66__weak_alias(clnt_spcreateerror,_clnt_spcreateerror)
67__weak_alias(clnt_sperrno,_clnt_sperrno)
68__weak_alias(clnt_sperror,_clnt_sperror)
69#endif
70
71static char *buf;
72static size_t buflen;
73
74static char *_buf __P((void));
75static char *auth_errmsg __P((enum auth_stat));
76
77static char *
78_buf()
79{
80
81	buflen = 256;
82	if (buf == 0)
83		buf = malloc(buflen);
84	return (buf);
85}
86
87/*
88 * Print reply error info
89 */
90char *
91clnt_sperror(rpch, s)
92	CLIENT *rpch;
93	const char *s;
94{
95	struct rpc_err e;
96	char *err;
97	char *str;
98	char *strstart;
99	size_t len, i;
100
101	_DIAGASSERT(rpch != NULL);
102	_DIAGASSERT(s != NULL);
103
104	str = _buf(); /* side effect: sets "buflen" */
105	if (str == 0)
106		return (0);
107	len = buflen;
108	strstart = str;
109	CLNT_GETERR(rpch, &e);
110
111	i = snprintf(str, len, "%s: ", s);
112	str += i;
113	len -= i;
114
115	(void)strncpy(str, clnt_sperrno(e.re_status), len - 1);
116	i = strlen(str);
117	str += i;
118	len -= i;
119
120	switch (e.re_status) {
121	case RPC_SUCCESS:
122	case RPC_CANTENCODEARGS:
123	case RPC_CANTDECODERES:
124	case RPC_TIMEDOUT:
125	case RPC_PROGUNAVAIL:
126	case RPC_PROCUNAVAIL:
127	case RPC_CANTDECODEARGS:
128	case RPC_SYSTEMERROR:
129	case RPC_UNKNOWNHOST:
130	case RPC_UNKNOWNPROTO:
131	case RPC_PMAPFAILURE:
132	case RPC_PROGNOTREGISTERED:
133	case RPC_FAILED:
134		break;
135
136	case RPC_CANTSEND:
137	case RPC_CANTRECV:
138		i = snprintf(str, len, "; errno = %s", strerror(e.re_errno));
139		str += i;
140		len -= i;
141		break;
142
143	case RPC_VERSMISMATCH:
144		i = snprintf(str, len, "; low version = %u, high version = %u",
145			e.re_vers.low, e.re_vers.high);
146		str += i;
147		len -= i;
148		break;
149
150	case RPC_AUTHERROR:
151		err = auth_errmsg(e.re_why);
152		i = snprintf(str, len, "; why = ");
153		str += i;
154		len -= i;
155		if (err != NULL) {
156			i = snprintf(str, len, "%s",err);
157		} else {
158			i = snprintf(str, len,
159				"(unknown authentication error - %d)",
160				(int) e.re_why);
161		}
162		str += i;
163		len -= i;
164		break;
165
166	case RPC_PROGVERSMISMATCH:
167		i = snprintf(str, len, "; low version = %u, high version = %u",
168			e.re_vers.low, e.re_vers.high);
169		str += i;
170		len -= i;
171		break;
172
173	default:	/* unknown */
174		i = snprintf(str, len, "; s1 = %u, s2 = %u",
175			e.re_lb.s1, e.re_lb.s2);
176		str += i;
177		len -= i;
178		break;
179	}
180	return(strstart) ;
181}
182
183void
184clnt_perror(rpch, s)
185	CLIENT *rpch;
186	const char *s;
187{
188
189	_DIAGASSERT(rpch != NULL);
190	_DIAGASSERT(s != NULL);
191
192	(void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s));
193}
194
195static const char *const rpc_errlist[] = {
196	[RPC_SUCCESS] =			"RPC: Success",
197	[RPC_CANTENCODEARGS] =		"RPC: Can't encode arguments",
198	[RPC_CANTDECODERES] =		"RPC: Can't decode result",
199	[RPC_CANTSEND] =		"RPC: Unable to send",
200	[RPC_CANTRECV] =		"RPC: Unable to receive",
201	[RPC_TIMEDOUT] =		"RPC: Timed out",
202	[RPC_VERSMISMATCH] =		"RPC: Incompatible versions of RPC",
203	[RPC_AUTHERROR] = 		"RPC: Authentication error",
204	[RPC_PROGUNAVAIL] =		"RPC: Program unavailable",
205	[RPC_PROGVERSMISMATCH] =	"RPC: Program/version mismatch",
206	[RPC_PROCUNAVAIL] =		"RPC: Procedure unavailable",
207	[RPC_CANTDECODEARGS] =		"RPC: Server can't decode arguments",
208	[RPC_SYSTEMERROR] =		"RPC: Remote system error",
209	[RPC_UNKNOWNHOST] =		"RPC: Unknown host",
210	[RPC_PMAPFAILURE] =		"RPC: Port mapper failure",
211	[RPC_PROGNOTREGISTERED] =	"RPC: Program not registered",
212	[RPC_FAILED] =			"RPC: Failed (unspecified error)",
213	[RPC_UNKNOWNPROTO] =		"RPC: Unknown protocol",
214	[RPC_UNKNOWNADDR] =		"RPC: Remote address unknown",
215	[RPC_TLIERROR] =		"RPC: Misc error in the TLI library",
216	[RPC_NOBROADCAST] =		"RPC: Broadcasting not supported",
217	[RPC_N2AXLATEFAILURE] =		"RPC: Name -> addr translation failed",
218	[RPC_INPROGRESS] =		"RPC: In progress",
219	[RPC_STALERACHANDLE] =		"RPC: Stale handle",
220};
221
222
223/*
224 * This interface for use by clntrpc
225 */
226char *
227clnt_sperrno(stat)
228	enum clnt_stat stat;
229{
230	unsigned int errnum = stat;
231	const char *msg;
232
233	msg = NULL;
234	if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0]))) {
235		msg = rpc_errlist[errnum];
236	}
237	if (msg == NULL) {
238		msg = "RPC: (unknown error code)";
239	}
240	return __UNCONST(msg);
241}
242
243void
244clnt_perrno(num)
245	enum clnt_stat num;
246{
247	(void) fprintf(stderr, "%s\n", clnt_sperrno(num));
248}
249
250
251char *
252clnt_spcreateerror(s)
253	const char *s;
254{
255	char *str;
256	size_t len, i;
257
258	_DIAGASSERT(s != NULL);
259
260	str = _buf(); /* side effect: sets "buflen" */
261	if (str == 0)
262		return(0);
263	len = buflen;
264	i = snprintf(str, len, "%s: ", s);
265	len -= i;
266	(void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1);
267	switch (rpc_createerr.cf_stat) {
268	case RPC_PMAPFAILURE:
269		(void) strncat(str, " - ", len - 1);
270		(void) strncat(str,
271		    clnt_sperrno(rpc_createerr.cf_error.re_status), len - 4);
272		break;
273
274	case RPC_SYSTEMERROR:
275		(void)strncat(str, " - ", len - 1);
276		(void)strncat(str, strerror(rpc_createerr.cf_error.re_errno),
277		    len - 4);
278		break;
279
280	case RPC_CANTSEND:
281	case RPC_CANTDECODERES:
282	case RPC_CANTENCODEARGS:
283	case RPC_SUCCESS:
284	case RPC_UNKNOWNPROTO:
285	case RPC_PROGNOTREGISTERED:
286	case RPC_FAILED:
287	case RPC_UNKNOWNHOST:
288	case RPC_CANTDECODEARGS:
289	case RPC_PROCUNAVAIL:
290	case RPC_PROGVERSMISMATCH:
291	case RPC_PROGUNAVAIL:
292	case RPC_AUTHERROR:
293	case RPC_VERSMISMATCH:
294	case RPC_TIMEDOUT:
295	case RPC_CANTRECV:
296	default:
297		break;
298	}
299	return (str);
300}
301
302void
303clnt_pcreateerror(s)
304	const char *s;
305{
306
307	_DIAGASSERT(s != NULL);
308
309	(void) fprintf(stderr, "%s\n", clnt_spcreateerror(s));
310}
311
312static const char *const auth_errlist[] = {
313	"Authentication OK",			/* 0 - AUTH_OK */
314	"Invalid client credential",		/* 1 - AUTH_BADCRED */
315	"Server rejected credential",		/* 2 - AUTH_REJECTEDCRED */
316	"Invalid client verifier", 		/* 3 - AUTH_BADVERF */
317	"Server rejected verifier", 		/* 4 - AUTH_REJECTEDVERF */
318	"Client credential too weak",		/* 5 - AUTH_TOOWEAK */
319	"Invalid server verifier",		/* 6 - AUTH_INVALIDRESP */
320	"Failed (unspecified error)"		/* 7 - AUTH_FAILED */
321};
322
323static char *
324auth_errmsg(stat)
325	enum auth_stat stat;
326{
327	unsigned int errnum = stat;
328
329	if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0])))
330		return __UNCONST(auth_errlist[errnum]);
331
332	return(NULL);
333}
334