xref: /illumos-gate/usr/src/uts/common/rpc/sec/authdesubr.c (revision 2bbdd445a21f9d61f4a0ca0faf05d5ceb2bd91f3)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2014 Gary Mills
24  * Copyright 2001 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 /*
32  * Portions of this source code were derived from Berkeley 4.3 BSD
33  * under license from the Regents of the University of California.
34  */
35 
36 /*
37  * Miscellaneous support routines for kernel implentation of AUTH_DES
38  */
39 
40 /*
41  *  rtime - get time from remote machine
42  *
43  *  sets time, obtaining value from host
44  *  on the udp/time socket.  Since timeserver returns
45  *  with time of day in seconds since Jan 1, 1900,  must
46  *  subtract 86400(365*70 + 17) to get time
47  *  since Jan 1, 1970, which is what get/settimeofday
48  *  uses.
49  */
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <sys/systm.h>
54 #include <sys/errno.h>
55 #include <sys/proc.h>
56 #include <sys/user.h>
57 #include <sys/socket.h>
58 #include <sys/sysmacros.h>
59 #include <netinet/in.h>
60 #include <rpc/rpc.h>
61 #include <sys/stream.h>
62 #include <sys/strsubr.h>
63 #include <sys/cred.h>
64 #include <sys/utsname.h>
65 #include <sys/vnode.h>
66 #include <sys/file.h>
67 #include <sys/uio.h>
68 #include <sys/systeminfo.h>
69 #include <rpc/rpcb_prot.h>
70 #include <sys/cmn_err.h>
71 
72 #define	TOFFSET ((uint32_t)86400 * (365 * 70 + (70 / 4)))
73 #define	WRITTEN ((uint32_t)86400 * (365 * 86 + (86 / 4)))
74 
75 #define	NC_INET	"inet"		/* XXX */
76 
77 int
78 rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
79 	struct timeval *timep, struct timeval *wait)
80 {
81 	int			error;
82 	int			timo;
83 	time_t			thetime;
84 	int32_t			srvtime;
85 	uint32_t		dummy;
86 	struct t_kunitdata	*unitdata;
87 	struct t_call		*server;
88 	TIUSER			*tiptr;
89 	int			type;
90 	int			uderr;
91 	int			i;
92 	int			retries;
93 	mblk_t			*mp;
94 	mblk_t			*mp2;
95 
96 	retries = 5;
97 	if (calltype == 0) {
98 again:
99 		RPCLOG0(8, "rtime: using old method\n");
100 		if ((error = t_kopen(NULL, synconfig->knc_rdev,
101 		    FREAD|FWRITE, &tiptr, CRED())) != 0) {
102 			RPCLOG(1, "rtime: t_kopen %d\n", error);
103 			return (-1);
104 		}
105 
106 		if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
107 			(void) t_kclose(tiptr, 1);
108 			RPCLOG(1, "rtime: t_kbind %d\n", error);
109 			return (-1);
110 		}
111 
112 		if (synconfig->knc_semantics == NC_TPI_CLTS) {
113 			if ((error = t_kalloc(tiptr, T_UNITDATA,
114 			    T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
115 				RPCLOG(1, "rtime: t_kalloc %d\n", error);
116 				(void) t_kclose(tiptr, 1);
117 				return (-1);
118 			}
119 
120 			unitdata->addr.len = addrp->len;
121 			bcopy(addrp->buf, unitdata->addr.buf,
122 			    unitdata->addr.len);
123 
124 			dummy = 0;
125 			unitdata->udata.buf = (caddr_t)&dummy;
126 			unitdata->udata.len = sizeof (dummy);
127 
128 			if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
129 			    0) {
130 				RPCLOG(1, "rtime: t_ksndudata %d\n", error);
131 				(void) t_kfree(tiptr, (char *)unitdata,
132 				    T_UNITDATA);
133 				(void) t_kclose(tiptr, 1);
134 				return (-1);
135 			}
136 
137 			timo = TIMEVAL_TO_TICK(wait);
138 
139 			RPCLOG(8, "rtime: timo %x\n", timo);
140 			if ((error = t_kspoll(tiptr, timo, READWAIT,
141 			    &type)) != 0) {
142 				RPCLOG(1, "rtime: t_kspoll %d\n", error);
143 				(void) t_kfree(tiptr, (char *)unitdata,
144 				    T_UNITDATA);
145 				(void) t_kclose(tiptr, 1);
146 				return (-1);
147 			}
148 
149 			if (type == 0) {
150 				RPCLOG0(1, "rtime: t_kspoll timed out\n");
151 				(void) t_kfree(tiptr, (char *)unitdata,
152 				    T_UNITDATA);
153 				(void) t_kclose(tiptr, 1);
154 				return (-1);
155 			}
156 
157 			error = t_krcvudata(tiptr, unitdata, &type, &uderr);
158 			if (error != 0) {
159 				RPCLOG(1, "rtime: t_krcvudata %d\n", error);
160 				(void) t_kfree(tiptr, (char *)unitdata,
161 				    T_UNITDATA);
162 				(void) t_kclose(tiptr, 1);
163 				if (error == EBADMSG && retries-- > 0)
164 					goto again;
165 				return (-1);
166 			}
167 
168 			if (type == T_UDERR) {
169 				if (bcmp(addrp->buf, unitdata->addr.buf,
170 				    unitdata->addr.len) != 0) {
171 				/*
172 				 * Response comes from some other
173 				 * destination:
174 				 * ignore it since it's not related to the
175 				 * request we just sent out.
176 				 */
177 					(void) t_kfree(tiptr, (char *)unitdata,
178 					    T_UNITDATA);
179 					(void) t_kclose(tiptr, 1);
180 					goto again;
181 				}
182 			}
183 
184 			if (type != T_DATA) {
185 				RPCLOG(1,
186 				    "rtime: t_krcvudata returned type %d\n",
187 				    type);
188 				(void) t_kfree(tiptr, (char *)unitdata,
189 				    T_UNITDATA);
190 				(void) t_kclose(tiptr, 1);
191 				if (retries-- == 0)
192 					return (-1);
193 				goto again;
194 			}
195 
196 			if (unitdata->udata.len < sizeof (uint32_t)) {
197 				RPCLOG(1, "rtime: bad rcvd length %d\n",
198 				    unitdata->udata.len);
199 				(void) t_kfree(tiptr, (char *)unitdata,
200 				    T_UNITDATA);
201 				(void) t_kclose(tiptr, 1);
202 				if (retries-- == 0)
203 					return (-1);
204 				goto again;
205 			}
206 
207 			thetime = (time_t)ntohl(
208 			    /* LINTED pointer alignment */
209 			    *(uint32_t *)unitdata->udata.buf);
210 			(void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
211 
212 		} else {
213 
214 			if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
215 			    (char **)&server)) != 0) {
216 				RPCLOG(1, "rtime: t_kalloc %d\n", error);
217 				(void) t_kclose(tiptr, 1);
218 				return (-1);
219 			}
220 
221 			server->addr.len = addrp->len;
222 			bcopy(addrp->buf, server->addr.buf, server->addr.len);
223 
224 			if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
225 				RPCLOG(1, "rtime: t_kconnect %d\n", error);
226 				(void) t_kfree(tiptr, (char *)server, T_CALL);
227 				(void) t_kclose(tiptr, 1);
228 				return (-1);
229 			}
230 			(void) t_kfree(tiptr, (char *)server, T_CALL);
231 
232 			timo = TIMEVAL_TO_TICK(wait);
233 
234 			RPCLOG(8, "rtime: timo %x\n", timo);
235 
236 			i = 0;
237 			dummy = 0;
238 
239 			/* now read up to 4 bytes from the TIME server */
240 			while (i < sizeof (dummy)) {
241 
242 				error = t_kspoll(tiptr, timo, READWAIT, &type);
243 				if (error != 0) {
244 					RPCLOG(1, "rtime: t_kspoll %d\n",
245 					    error);
246 					(void) t_kclose(tiptr, 1);
247 					return (-1);
248 				}
249 
250 				if (type == 0) {
251 					RPCLOG0(1,
252 					    "rtime: t_kspoll timed out\n");
253 					(void) t_kclose(tiptr, 1);
254 					return (-1);
255 				}
256 
257 				error = tli_recv(tiptr, &mp,
258 				    tiptr->fp->f_flag);
259 				if (error != 0) {
260 					RPCLOG(1, "rtime: tli_recv %d\n",
261 					    error);
262 					(void) t_kclose(tiptr, 1);
263 					return (-1);
264 				}
265 
266 				if (mp->b_datap->db_type != M_DATA) {
267 					RPCLOG(1, "rtime: wrong msg type %d\n",
268 					    mp->b_datap->db_type);
269 					RPCLOG(1,
270 					    "rtime: wrong msg type: read %d"
271 					    " bytes\n", i);
272 					(void) t_kclose(tiptr, 1);
273 					freemsg(mp);
274 					return (-1);
275 				}
276 
277 				mp2 = mp;
278 
279 				/*
280 				 * The outer loop iterates until we reach the
281 				 * end of the mblk chain.
282 				 */
283 				while (mp2 != NULL) {
284 
285 					/*
286 					 * The inner loop iterates until
287 					 * we've gotten 4 bytes or until
288 					 * the mblk is exhausted.
289 					 */
290 					while (i < sizeof (dummy) &&
291 					    mp2->b_rptr < mp2->b_wptr) {
292 
293 						i++;
294 
295 					/*
296 					 * We avoid big-endian/little-endian
297 					 * issues by serializing the result
298 					 * one byte at a time.
299 					 */
300 						dummy <<= 8;
301 						dummy += ((*mp2->b_rptr) &
302 						    0xFF);
303 
304 						mp2->b_rptr++;
305 					}
306 
307 					mp2 = mp2->b_cont;
308 				}
309 
310 			freemsg(mp);
311 			}
312 
313 			thetime = (time_t)dummy;
314 		}
315 
316 		(void) t_kclose(tiptr, 1);
317 
318 	} else {
319 		CLIENT			*client;
320 		struct timeval		timout;
321 
322 		RPCLOG0(8, "rtime: using new method\n");
323 
324 new_again:
325 		/*
326 		 *	We talk to rpcbind.
327 		 */
328 		error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
329 		    (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);
330 
331 		if (error != 0) {
332 			RPCLOG(1,
333 			    "rtime: clnt_tli_kcreate returned %d\n", error);
334 			return (-1);
335 		}
336 		timout.tv_sec = 60;
337 		timout.tv_usec = 0;
338 		error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
339 		    NULL, (xdrproc_t)xdr_u_int,
340 		    (caddr_t)&srvtime, timout);
341 		thetime = srvtime;
342 		auth_destroy(client->cl_auth);
343 		clnt_destroy(client);
344 		if (error == RPC_UDERROR) {
345 			if (retries-- > 0)
346 				goto new_again;
347 		}
348 		if (error != RPC_SUCCESS) {
349 			RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
350 			    error);
351 			error = EIO;
352 			return (-1);
353 		}
354 	}
355 
356 	if (calltype != 0)
357 		thetime += TOFFSET;
358 
359 	RPCLOG(8, "rtime: thetime = %lx\n", thetime);
360 
361 	if (thetime < WRITTEN) {
362 		RPCLOG(1, "rtime: time returned is too far in past %lx",
363 		    thetime);
364 		RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
365 		return (-1);
366 	}
367 	thetime -= TOFFSET;
368 
369 	timep->tv_sec = thetime;
370 	RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
371 	RPCLOG(8, "rtime: machine time  = %lx\n", gethrestime_sec());
372 	timep->tv_usec = 0;
373 	RPCLOG0(8, "rtime: returning success\n");
374 	return (0);
375 }
376 
377 /*
378  * What is my network name?
379  * WARNING: this gets the network name in sun unix format.
380  * Other operating systems (non-unix) are free to put something else
381  * here.
382  *
383  * Return 0 on success
384  * Return RPC errors (non-zero values) if failed.
385  */
386 enum clnt_stat
387 kgetnetname(char *netname)
388 {
389 	return (key_getnetname(netname, CRED()));
390 }
391