xref: /illumos-gate/usr/src/uts/common/rpc/sec/authdesubr.c (revision 75eba5b6d79ed4d2ce3daf7b2806306b6b69a938)
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 2001 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 /*
31  * Portions of this source code were derived from Berkeley 4.3 BSD
32  * under license from the Regents of the University of California.
33  */
34 
35 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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, T_UDATA|T_ADDR,
115 			(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, 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)) != 0) {
129 			    RPCLOG(1, "rtime: t_ksndudata %d\n", error);
130 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
131 			    (void) t_kclose(tiptr, 1);
132 			    return (-1);
133 		    }
134 
135 		    timo = TIMEVAL_TO_TICK(wait);
136 
137 		    RPCLOG(8, "rtime: timo %x\n", timo);
138 		    if ((error = t_kspoll(tiptr, timo, READWAIT, &type)) != 0) {
139 			    RPCLOG(1, "rtime: t_kspoll %d\n", error);
140 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
141 			    (void) t_kclose(tiptr, 1);
142 			    return (-1);
143 		    }
144 
145 		    if (type == 0) {
146 			    RPCLOG0(1, "rtime: t_kspoll timed out\n");
147 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
148 			    (void) t_kclose(tiptr, 1);
149 			    return (-1);
150 		    }
151 
152 		    error = t_krcvudata(tiptr, unitdata, &type, &uderr);
153 		    if (error != 0) {
154 			    RPCLOG(1, "rtime: t_krcvudata %d\n", error);
155 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
156 			    (void) t_kclose(tiptr, 1);
157 			    return (-1);
158 		    }
159 
160 		    if (type == T_UDERR) {
161 			    if (bcmp(addrp->buf, unitdata->addr.buf,
162 				unitdata->addr.len) != 0) {
163 				/*
164 				 * Response comes from some other
165 				 * destination:
166 				 * ignore it since it's not related to the
167 				 * request we just sent out.
168 				 */
169 				    (void) t_kfree(tiptr, (char *)unitdata,
170 					T_UNITDATA);
171 				    (void) t_kclose(tiptr, 1);
172 				    goto again;
173 			    }
174 		    }
175 
176 		    if (type != T_DATA) {
177 			    RPCLOG(1, "rtime: t_krcvudata returned type %d\n",
178 				type);
179 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
180 			    (void) t_kclose(tiptr, 1);
181 			    if (retries-- == 0)
182 				    return (-1);
183 			    goto again;
184 		    }
185 
186 		    if (unitdata->udata.len < sizeof (uint32_t)) {
187 			    RPCLOG(1, "rtime: bad rcvd length %d\n",
188 				unitdata->udata.len);
189 			    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
190 			    (void) t_kclose(tiptr, 1);
191 			    if (retries-- == 0)
192 				    return (-1);
193 			    goto again;
194 		    }
195 
196 		    /* LINTED pointer alignment */
197 		    thetime = (time_t)ntohl(*(uint32_t *)unitdata->udata.buf);
198 		    (void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);
199 
200 		} else {
201 
202 		    if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
203 			(char **)&server)) != 0) {
204 			    RPCLOG(1, "rtime: t_kalloc %d\n", error);
205 			    (void) t_kclose(tiptr, 1);
206 			    return (-1);
207 		    }
208 
209 		    server->addr.len = addrp->len;
210 		    bcopy(addrp->buf, server->addr.buf, server->addr.len);
211 
212 		    if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
213 			    RPCLOG(1, "rtime: t_kconnect %d\n", error);
214 			    (void) t_kfree(tiptr, (char *)server, T_CALL);
215 			    (void) t_kclose(tiptr, 1);
216 			    return (-1);
217 		    }
218 		    (void) t_kfree(tiptr, (char *)server, T_CALL);
219 
220 		    timo = TIMEVAL_TO_TICK(wait);
221 
222 		    RPCLOG(8, "rtime: timo %x\n", timo);
223 
224 		    i = 0;
225 		    dummy = 0;
226 
227 		    /* now read up to 4 bytes from the TIME server */
228 		    while (i < sizeof (dummy)) {
229 
230 			error = t_kspoll(tiptr, timo, READWAIT, &type);
231 			if (error != 0) {
232 				RPCLOG(1, "rtime: t_kspoll %d\n", error);
233 				(void) t_kclose(tiptr, 1);
234 				return (-1);
235 			}
236 
237 			if (type == 0) {
238 				RPCLOG0(1, "rtime: t_kspoll timed out\n");
239 				(void) t_kclose(tiptr, 1);
240 				return (-1);
241 			}
242 
243 			error = tli_recv(tiptr, &mp, tiptr->fp->f_flag);
244 			if (error != 0) {
245 				RPCLOG(1, "rtime: tli_recv %d\n", error);
246 				(void) t_kclose(tiptr, 1);
247 				return (-1);
248 			}
249 
250 			if (mp->b_datap->db_type != M_DATA) {
251 				RPCLOG(1, "rtime: wrong msg type %d\n",
252 					mp->b_datap->db_type);
253 				RPCLOG(1, "rtime: wrong msg type: read %d"
254 					" bytes\n", i);
255 				(void) t_kclose(tiptr, 1);
256 				freemsg(mp);
257 				return (-1);
258 			}
259 
260 			mp2 = mp;
261 
262 			/*
263 			 * The outer loop iterates until we reach the end of
264 			 * the mblk chain.
265 			 */
266 			while (mp2 != NULL) {
267 
268 				/*
269 				 * The inner loop iterates until we've gotten
270 				 * 4 bytes or until the mblk is exhausted.
271 				 */
272 				while (i < sizeof (dummy) &&
273 				    mp2->b_rptr < mp2->b_wptr) {
274 
275 					i++;
276 
277 					/*
278 					 * We avoid big-endian/little-endian
279 					 * issues by serializing the result
280 					 * one byte at a time.
281 					 */
282 					dummy <<= 8;
283 					dummy += ((*mp2->b_rptr) & 0xFF);
284 
285 					mp2->b_rptr++;
286 				}
287 
288 				mp2 = mp2->b_cont;
289 			}
290 
291 			freemsg(mp);
292 		    }
293 
294 		    thetime = (time_t)dummy;
295 		}
296 
297 		(void) t_kclose(tiptr, 1);
298 
299 	} else {
300 		CLIENT			*client;
301 		struct timeval		timout;
302 
303 		RPCLOG0(8, "rtime: using new method\n");
304 
305 new_again:
306 		/*
307 		 *	We talk to rpcbind.
308 		 */
309 		error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
310 		    (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);
311 
312 		if (error != 0) {
313 			RPCLOG(1,
314 			    "rtime: clnt_tli_kcreate returned %d\n", error);
315 			return (-1);
316 		}
317 		timout.tv_sec = 60;
318 		timout.tv_usec = 0;
319 		error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
320 		    NULL, (xdrproc_t)xdr_u_int,
321 		    (caddr_t)&srvtime, timout);
322 		thetime = srvtime;
323 		auth_destroy(client->cl_auth);
324 		clnt_destroy(client);
325 		if (error == RPC_UDERROR) {
326 			if (retries-- > 0)
327 				goto new_again;
328 		}
329 		if (error != RPC_SUCCESS) {
330 			RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
331 			    error);
332 			error = EIO;
333 			return (-1);
334 		}
335 	}
336 
337 	if (calltype != 0)
338 		thetime += TOFFSET;
339 
340 	RPCLOG(8, "rtime: thetime = %lx\n", thetime);
341 
342 	if (thetime < WRITTEN) {
343 		RPCLOG(1, "rtime: time returned is too far in past %lx",
344 		    thetime);
345 		RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
346 		return (-1);
347 	}
348 	thetime -= TOFFSET;
349 
350 	timep->tv_sec = thetime;
351 	RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
352 	RPCLOG(8, "rtime: machine time  = %lx\n", gethrestime_sec());
353 	timep->tv_usec = 0;
354 	RPCLOG0(8, "rtime: returning success\n");
355 	return (0);
356 }
357 
358 /*
359  * What is my network name?
360  * WARNING: this gets the network name in sun unix format.
361  * Other operating systems (non-unix) are free to put something else
362  * here.
363  *
364  * Return 0 on success
365  * Return RPC errors (non-zero values) if failed.
366  */
367 enum clnt_stat
368 kgetnetname(char *netname)
369 {
370 	return (key_getnetname(netname, CRED()));
371 }
372