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