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