1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30  * Portions of this source code were derived from Berkeley
31  * 4.3 BSD under license from the Regents of the University of
32  * California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36 
37 /*
38  * clnt_perror.c
39  *
40  */
41 
42 #include "mt.h"
43 #include "rpc_mt.h"
44 #include <stdio.h>
45 #include <libintl.h>
46 #include <string.h>
47 #include <rpc/types.h>
48 #include <rpc/auth.h>
49 #include <sys/tiuser.h>
50 #include <rpc/clnt.h>
51 #include <stdlib.h>
52 #include <syslog.h>
53 #include <string.h>
54 
55 extern char *netdir_sperror();
56 
57 const char __nsl_dom[]  = "SUNW_OST_NETRPC";
58 
59 #define	ERRBUFSZ	512
60 
61 static char *
62 __buf(void)
63 {
64 	char *buf;
65 	static char buf_main[ERRBUFSZ];
66 	static pthread_key_t perror_key = PTHREAD_ONCE_KEY_NP;
67 
68 	buf = thr_main()? buf_main :
69 		thr_get_storage(&perror_key, ERRBUFSZ, free);
70 	if (buf == NULL)
71 		syslog(LOG_WARNING,
72 		"clnt_sperror: malloc failed when trying to create buffer\n");
73 	return (buf);
74 }
75 
76 static char *
77 auth_errmsg(enum auth_stat stat)
78 {
79 	switch (stat) {
80 	case AUTH_OK:
81 		return (dgettext(__nsl_dom, "Authentication OK"));
82 	case AUTH_BADCRED:
83 		return (dgettext(__nsl_dom, "Invalid client credential"));
84 	case AUTH_REJECTEDCRED:
85 		return (dgettext(__nsl_dom, "Server rejected credential"));
86 	case AUTH_BADVERF:
87 		return (dgettext(__nsl_dom, "Invalid client verifier"));
88 	case AUTH_REJECTEDVERF:
89 		return (dgettext(__nsl_dom, "Server rejected verifier"));
90 	case AUTH_TOOWEAK:
91 		return (dgettext(__nsl_dom, "Client credential too weak"));
92 	case AUTH_INVALIDRESP:
93 		return (dgettext(__nsl_dom, "Invalid server verifier"));
94 	case AUTH_FAILED:
95 		return (dgettext(__nsl_dom, "Failed (unspecified error)"));
96 
97 	/* kerberos specific */
98 	case AUTH_DECODE:
99 		return (dgettext(__nsl_dom, "Could not decode authenticator"));
100 	case AUTH_TIMEEXPIRE:
101 		return (dgettext(__nsl_dom, "Time of credential expired"));
102 	case AUTH_TKT_FILE:
103 		return (dgettext(__nsl_dom,
104 			"Something wrong with kerberos ticket file"));
105 	case AUTH_NET_ADDR:
106 		return (dgettext(__nsl_dom,
107 		"Incorrect network address in kerberos ticket"));
108 	case AUTH_KERB_GENERIC:
109 		return (dgettext(__nsl_dom, "Kerberos generic error"));
110 	}
111 	return (dgettext(__nsl_dom, "Unknown authentication error"));
112 }
113 
114 /*
115  * Return string reply error info. For use after clnt_call()
116  */
117 
118 #define	REMAINDER	(ERRBUFSZ - (str - strstart))
119 
120 char *
121 clnt_sperror(const CLIENT *cl, const char *s)
122 {
123 	struct rpc_err e;
124 	char *err;
125 	char *str = __buf();
126 	char *strstart = str;
127 
128 	if (str == NULL)
129 		return (NULL);
130 	CLNT_GETERR((CLIENT *) cl, &e);
131 
132 	(void) snprintf(str, ERRBUFSZ, "%s: ", s);
133 	str += strlcat(str, clnt_sperrno(e.re_status), ERRBUFSZ);
134 
135 	switch (e.re_status) {
136 	case RPC_SUCCESS:
137 	case RPC_CANTENCODEARGS:
138 	case RPC_CANTDECODERES:
139 	case RPC_TIMEDOUT:
140 	case RPC_PROGUNAVAIL:
141 	case RPC_PROCUNAVAIL:
142 	case RPC_CANTDECODEARGS:
143 	case RPC_SYSTEMERROR:
144 	case RPC_UNKNOWNHOST:
145 	case RPC_UNKNOWNPROTO:
146 	case RPC_UNKNOWNADDR:
147 	case RPC_NOBROADCAST:
148 	case RPC_RPCBFAILURE:
149 	case RPC_PROGNOTREGISTERED:
150 	case RPC_FAILED:
151 		break;
152 
153 	case RPC_N2AXLATEFAILURE:
154 		(void) snprintf(str, REMAINDER, "; %s", netdir_sperror());
155 		str += strlen(str);
156 		break;
157 
158 	case RPC_TLIERROR:
159 		(void) snprintf(str, REMAINDER, "; %s", t_errlist[e.re_terrno]);
160 		str += strlen(str);
161 		if (e.re_errno) {
162 			(void) snprintf(str, REMAINDER,
163 			    "; %s", strerror(e.re_errno));
164 			str += strlen(str);
165 		}
166 		break;
167 
168 	case RPC_CANTSTORE:
169 	case RPC_CANTSEND:
170 	case RPC_CANTRECV:
171 		if (e.re_errno) {
172 			(void) snprintf(str, REMAINDER, "; errno = %s",
173 					strerror(e.re_errno));
174 			str += strlen(str);
175 		}
176 		if (e.re_terrno) {
177 			(void) snprintf(str, REMAINDER,
178 				"; %s", t_errlist[e.re_terrno]);
179 			str += strlen(str);
180 		}
181 		break;
182 
183 	case RPC_VERSMISMATCH:
184 		(void) snprintf(str, REMAINDER,
185 				"; low version = %lu, high version = %lu",
186 				e.re_vers.low, e.re_vers.high);
187 		str += strlen(str);
188 		break;
189 
190 	case RPC_AUTHERROR:
191 		err = auth_errmsg(e.re_why);
192 		(void) snprintf(str, REMAINDER, "; why = ");
193 		str += strlen(str);
194 		if (err != NULL) {
195 			(void) snprintf(str, REMAINDER, "%s", err);
196 		} else {
197 			(void) snprintf(str, REMAINDER,
198 				"(unknown authentication error - %d)",
199 				(int)e.re_why);
200 		}
201 		str += strlen(str);
202 		break;
203 
204 	case RPC_PROGVERSMISMATCH:
205 		(void) snprintf(str, REMAINDER,
206 				"; low version = %lu, high version = %lu",
207 				e.re_vers.low, e.re_vers.high);
208 		str += strlen(str);
209 		break;
210 
211 	default:	/* unknown */
212 		(void) snprintf(str, REMAINDER, "; s1 = %lu, s2 = %lu",
213 				e.re_lb.s1, e.re_lb.s2);
214 		str += strlen(str);
215 		break;
216 	}
217 	return (strstart);
218 }
219 #undef	REMAINDER
220 
221 void
222 clnt_perror(const CLIENT *cl, const char *s)
223 {
224 	(void) fprintf(stderr, "%s\n", clnt_sperror(cl, s));
225 }
226 
227 void
228 clnt_perrno(const enum clnt_stat num)
229 {
230 	(void) fprintf(stderr, "%s\n", clnt_sperrno(num));
231 }
232 
233 /*
234  * Why a client handle could not be created
235  */
236 char *
237 clnt_spcreateerror(const char *s)
238 {
239 	char *errstr;
240 	char *str = __buf();
241 
242 	if (str == NULL)
243 		return (NULL);
244 	(void) snprintf(str, ERRBUFSZ, "%s: ", s);
245 	(void) strlcat(str, clnt_sperrno(rpc_createerr.cf_stat), ERRBUFSZ);
246 
247 	switch (rpc_createerr.cf_stat) {
248 	case RPC_N2AXLATEFAILURE:
249 		(void) strlcat(str, " - ", ERRBUFSZ);
250 		(void) strlcat(str, netdir_sperror(), ERRBUFSZ);
251 		break;
252 
253 	case RPC_RPCBFAILURE:
254 		(void) strlcat(str, " - ", ERRBUFSZ);
255 		(void) strlcat(str,
256 			clnt_sperrno(rpc_createerr.cf_error.re_status),
257 			ERRBUFSZ);
258 		break;
259 
260 	case RPC_SYSTEMERROR:
261 		(void) strlcat(str, " - ", ERRBUFSZ);
262 		errstr = strerror(rpc_createerr.cf_error.re_errno);
263 		if (errstr != NULL)
264 			(void) strlcat(str, errstr, ERRBUFSZ);
265 		else
266 			(void) snprintf(&str[strlen(str)],
267 			    ERRBUFSZ - strlen(str), "Error %d",
268 			    rpc_createerr.cf_error.re_errno);
269 		break;
270 
271 	case RPC_TLIERROR:
272 		(void) strlcat(str, " - ", ERRBUFSZ);
273 		if ((rpc_createerr.cf_error.re_terrno > 0) &&
274 			(rpc_createerr.cf_error.re_terrno < t_nerr)) {
275 			(void) strlcat(str,
276 				t_errlist[rpc_createerr.cf_error.re_terrno],
277 				ERRBUFSZ);
278 			if (rpc_createerr.cf_error.re_terrno == TSYSERR) {
279 				char *err;
280 				err = strerror(rpc_createerr.cf_error.re_errno);
281 				if (err) {
282 					(void) strlcat(str, " (", ERRBUFSZ);
283 					(void) strlcat(str, err, ERRBUFSZ);
284 					(void) strlcat(str, ")", ERRBUFSZ);
285 				}
286 			}
287 		} else {
288 			(void) snprintf(&str[strlen(str)],
289 			    ERRBUFSZ - strlen(str),
290 			    dgettext(__nsl_dom,  "TLI Error %d"),
291 			    rpc_createerr.cf_error.re_terrno);
292 		}
293 		errstr = strerror(rpc_createerr.cf_error.re_errno);
294 		if (errstr != NULL)
295 			(void) strlcat(str, errstr, ERRBUFSZ);
296 		else
297 			(void) snprintf(&str[strlen(str)],
298 			    ERRBUFSZ - strlen(str), "Error %d",
299 			    rpc_createerr.cf_error.re_errno);
300 		break;
301 
302 	case RPC_AUTHERROR:
303 		(void) strlcat(str, " - ", ERRBUFSZ);
304 		(void) strlcat(str,
305 			auth_errmsg(rpc_createerr.cf_error.re_why), ERRBUFSZ);
306 		break;
307 	}
308 	return (str);
309 }
310 
311 void
312 clnt_pcreateerror(const char *s)
313 {
314 	(void) fprintf(stderr, "%s\n", clnt_spcreateerror(s));
315 }
316 
317 /*
318  * This interface for use by rpc_call() and rpc_broadcast()
319  */
320 const char *
321 clnt_sperrno(const enum clnt_stat stat)
322 {
323 	switch (stat) {
324 	case RPC_SUCCESS:
325 		return (dgettext(__nsl_dom, "RPC: Success"));
326 	case RPC_CANTENCODEARGS:
327 		return (dgettext(__nsl_dom, "RPC: Can't encode arguments"));
328 	case RPC_CANTDECODERES:
329 		return (dgettext(__nsl_dom, "RPC: Can't decode result"));
330 	case RPC_CANTSTORE:
331 		return (dgettext(__nsl_dom, "RPC: Can't store request"));
332 	case RPC_CANTSEND:
333 		return (dgettext(__nsl_dom, "RPC: Unable to send"));
334 	case RPC_CANTRECV:
335 		return (dgettext(__nsl_dom, "RPC: Unable to receive"));
336 	case RPC_TIMEDOUT:
337 		return (dgettext(__nsl_dom, "RPC: Timed out"));
338 	case RPC_VERSMISMATCH:
339 		return (dgettext(__nsl_dom,
340 			"RPC: Incompatible versions of RPC"));
341 	case RPC_AUTHERROR:
342 		return (dgettext(__nsl_dom, "RPC: Authentication error"));
343 	case RPC_PROGUNAVAIL:
344 		return (dgettext(__nsl_dom, "RPC: Program unavailable"));
345 	case RPC_PROGVERSMISMATCH:
346 		return (dgettext(__nsl_dom, "RPC: Program/version mismatch"));
347 	case RPC_PROCUNAVAIL:
348 		return (dgettext(__nsl_dom, "RPC: Procedure unavailable"));
349 	case RPC_CANTDECODEARGS:
350 		return (dgettext(__nsl_dom,
351 			"RPC: Server can't decode arguments"));
352 
353 	case RPC_SYSTEMERROR:
354 		return (dgettext(__nsl_dom, "RPC: Remote system error"));
355 	case RPC_UNKNOWNHOST:
356 		return (dgettext(__nsl_dom, "RPC: Unknown host"));
357 	case RPC_UNKNOWNPROTO:
358 		return (dgettext(__nsl_dom, "RPC: Unknown protocol"));
359 	case RPC_RPCBFAILURE:
360 		return (dgettext(__nsl_dom, "RPC: Rpcbind failure"));
361 	case RPC_N2AXLATEFAILURE:
362 		return (dgettext(__nsl_dom,
363 			"RPC: Name to address translation failed"));
364 	case RPC_NOBROADCAST:
365 		return (dgettext(__nsl_dom, "RPC: Broadcast not supported"));
366 	case RPC_PROGNOTREGISTERED:
367 		return (dgettext(__nsl_dom, "RPC: Program not registered"));
368 	case RPC_UNKNOWNADDR:
369 		return (dgettext(__nsl_dom,
370 			"RPC: Remote server address unknown"));
371 	case RPC_TLIERROR:
372 		return (dgettext(__nsl_dom, "RPC: Miscellaneous tli error"));
373 	case RPC_FAILED:
374 		return (dgettext(__nsl_dom, "RPC: Failed (unspecified error)"));
375 	case RPC_INPROGRESS:
376 		return (dgettext(__nsl_dom, "RPC: RAC call in progress"));
377 	case RPC_STALERACHANDLE:
378 		return (dgettext(__nsl_dom, "RPC: Stale RAC handle"));
379 	case RPC_CANTCONNECT:
380 		return (dgettext(__nsl_dom, "RPC: Couldn't make connection"));
381 	case RPC_XPRTFAILED:
382 		return (dgettext(__nsl_dom,
383 			"RPC: Received disconnect from remote"));
384 	case RPC_CANTCREATESTREAM:
385 		return (dgettext(__nsl_dom, "RPC: Can't push RPC module"));
386 	}
387 	return (dgettext(__nsl_dom, "RPC: (unknown error code)"));
388 }
389