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