xref: /freebsd/lib/libc/rpc/auth_des.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2009, Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Sun Microsystems, Inc. nor the names of its
15  *   contributors may be used to endorse or promote products derived
16  *   from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*
31  * Copyright (c) 1988 by Sun Microsystems, Inc.
32  */
33 /*
34  * auth_des.c, client-side implementation of DES authentication
35  */
36 
37 #include "namespace.h"
38 #include "reentrant.h"
39 #include <err.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <rpc/des_crypt.h>
45 #include <syslog.h>
46 #include <rpc/types.h>
47 #include <rpc/auth.h>
48 #include <rpc/auth_des.h>
49 #include <rpc/clnt.h>
50 #include <rpc/xdr.h>
51 #include <sys/socket.h>
52 #undef NIS
53 #include <rpcsvc/nis.h>
54 #include "un-namespace.h"
55 #include "mt_misc.h"
56 
57 #define USEC_PER_SEC		1000000
58 #define RTIME_TIMEOUT		5	/* seconds to wait for sync */
59 
60 #define AUTH_PRIVATE(auth)	(struct ad_private *) auth->ah_private
61 #define ALLOC(object_type)	(object_type *) mem_alloc(sizeof(object_type))
62 #define FREE(ptr, size)		mem_free((char *)(ptr), (int) size)
63 #define ATTEMPT(xdr_op)		if (!(xdr_op)) return (FALSE)
64 
65 extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *);
66 extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *);
67 extern int key_encryptsession_pk(char *, netobj *, des_block *);
68 
69 extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *,
70 	char **, char **);
71 
72 /*
73  * DES authenticator operations vector
74  */
75 static void	authdes_nextverf(AUTH *);
76 static bool_t	authdes_marshal(AUTH *, XDR *);
77 static bool_t	authdes_validate(AUTH *, struct opaque_auth *);
78 static bool_t	authdes_refresh(AUTH *, void *);
79 static void	authdes_destroy(AUTH *);
80 
81 static struct auth_ops *authdes_ops(void);
82 
83 /*
84  * This struct is pointed to by the ah_private field of an "AUTH *"
85  */
86 struct ad_private {
87 	char *ad_fullname; 		/* client's full name */
88 	u_int ad_fullnamelen;		/* length of name, rounded up */
89 	char *ad_servername; 		/* server's full name */
90 	u_int ad_servernamelen;		/* length of name, rounded up */
91 	u_int ad_window;	  	/* client specified window */
92 	bool_t ad_dosync;		/* synchronize? */
93 	struct netbuf ad_syncaddr;	/* remote host to synch with */
94 	char *ad_timehost;		/* remote host to synch with */
95 	struct timeval ad_timediff;	/* server's time - client's time */
96 	u_int ad_nickname;		/* server's nickname for client */
97 	struct authdes_cred ad_cred;	/* storage for credential */
98 	struct authdes_verf ad_verf;	/* storage for verifier */
99 	struct timeval ad_timestamp;	/* timestamp sent */
100 	des_block ad_xkey;		/* encrypted conversation key */
101 	u_char ad_pkey[1024];		/* Server's actual public key */
102 	char *ad_netid;			/* Timehost netid */
103 	char *ad_uaddr;			/* Timehost uaddr */
104 	nis_server *ad_nis_srvr;	/* NIS+ server struct */
105 };
106 
107 AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *,
108 	const des_block *, nis_server *);
109 
110 /*
111  * documented version of authdes_seccreate
112  */
113 /*
114 	servername:	network name of server
115 	win:		time to live
116 	timehost:	optional hostname to sync with
117 	ckey:		optional conversation key to use
118 */
119 
120 AUTH *
authdes_seccreate(const char * servername,const u_int win,const char * timehost,const des_block * ckey)121 authdes_seccreate(const char *servername, const u_int win,
122 	const char *timehost, const des_block *ckey)
123 {
124 	u_char  pkey_data[1024];
125 	netobj  pkey;
126 	AUTH    *dummy;
127 
128 	if (! getpublickey(servername, (char *) pkey_data)) {
129 		syslog(LOG_ERR,
130 		    "authdes_seccreate: no public key found for %s",
131 		    servername);
132 		return (NULL);
133 	}
134 
135 	pkey.n_bytes = (char *) pkey_data;
136 	pkey.n_len = (u_int)strlen((char *)pkey_data) + 1;
137 	dummy = authdes_pk_seccreate(servername, &pkey, win, timehost,
138 	    ckey, NULL);
139 	return (dummy);
140 }
141 
142 /*
143  * Slightly modified version of authdessec_create which takes the public key
144  * of the server principal as an argument. This spares us a call to
145  * getpublickey() which in the nameserver context can cause a deadlock.
146  */
147 AUTH *
authdes_pk_seccreate(const char * servername,netobj * pkey,u_int window,const char * timehost,const des_block * ckey,nis_server * srvr)148 authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window,
149 	const char *timehost, const des_block *ckey, nis_server *srvr)
150 {
151 	AUTH *auth;
152 	struct ad_private *ad;
153 	char namebuf[MAXNETNAMELEN+1];
154 
155 	/*
156 	 * Allocate everything now
157 	 */
158 	auth = ALLOC(AUTH);
159 	if (auth == NULL) {
160 		syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
161 		return (NULL);
162 	}
163 	ad = ALLOC(struct ad_private);
164 	if (ad == NULL) {
165 		syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
166 		goto failed;
167 	}
168 	ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */
169 	ad->ad_timehost = NULL;
170 	ad->ad_netid = NULL;
171 	ad->ad_uaddr = NULL;
172 	ad->ad_nis_srvr = NULL;
173 	ad->ad_timediff.tv_sec = 0;
174 	ad->ad_timediff.tv_usec = 0;
175 	memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len);
176 	if (!getnetname(namebuf))
177 		goto failed;
178 	ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf));
179 	ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1);
180 	ad->ad_servernamelen = strlen(servername);
181 	ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1);
182 
183 	if (ad->ad_fullname == NULL || ad->ad_servername == NULL) {
184 		syslog(LOG_ERR, "authdes_seccreate: out of memory");
185 		goto failed;
186 	}
187 	if (timehost != NULL) {
188 		ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1);
189 		if (ad->ad_timehost == NULL) {
190 			syslog(LOG_ERR, "authdes_seccreate: out of memory");
191 			goto failed;
192 		}
193 		memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1);
194 		ad->ad_dosync = TRUE;
195 	} else if (srvr != NULL) {
196 		ad->ad_nis_srvr = srvr;	/* transient */
197 		ad->ad_dosync = TRUE;
198 	} else {
199 		ad->ad_dosync = FALSE;
200 	}
201 	memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1);
202 	memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1);
203 	ad->ad_window = window;
204 	if (ckey == NULL) {
205 		if (key_gendes(&auth->ah_key) < 0) {
206 			syslog(LOG_ERR,
207 	    "authdes_seccreate: keyserv(1m) is unable to generate session key");
208 			goto failed;
209 		}
210 	} else {
211 		auth->ah_key = *ckey;
212 	}
213 
214 	/*
215 	 * Set up auth handle
216 	 */
217 	auth->ah_cred.oa_flavor = AUTH_DES;
218 	auth->ah_verf.oa_flavor = AUTH_DES;
219 	auth->ah_ops = authdes_ops();
220 	auth->ah_private = (caddr_t)ad;
221 
222 	if (!authdes_refresh(auth, NULL)) {
223 		goto failed;
224 	}
225 	ad->ad_nis_srvr = NULL; /* not needed any longer */
226 	return (auth);
227 
228 failed:
229 	if (auth)
230 		FREE(auth, sizeof (AUTH));
231 	if (ad) {
232 		if (ad->ad_fullname)
233 			FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
234 		if (ad->ad_servername)
235 			FREE(ad->ad_servername, ad->ad_servernamelen + 1);
236 		if (ad->ad_timehost)
237 			FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
238 		if (ad->ad_netid)
239 			FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
240 		if (ad->ad_uaddr)
241 			FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
242 		FREE(ad, sizeof (struct ad_private));
243 	}
244 	return (NULL);
245 }
246 
247 /*
248  * Implement the five authentication operations
249  */
250 
251 
252 /*
253  * 1. Next Verifier
254  */
255 /*ARGSUSED*/
256 static void
authdes_nextverf(AUTH * auth __unused)257 authdes_nextverf(AUTH *auth __unused)
258 {
259 	/* what the heck am I supposed to do??? */
260 }
261 
262 
263 /*
264  * 2. Marshal
265  */
266 static bool_t
authdes_marshal(AUTH * auth,XDR * xdrs)267 authdes_marshal(AUTH *auth, XDR *xdrs)
268 {
269 /* LINTED pointer alignment */
270 	struct ad_private *ad = AUTH_PRIVATE(auth);
271 	struct authdes_cred *cred = &ad->ad_cred;
272 	struct authdes_verf *verf = &ad->ad_verf;
273 	des_block cryptbuf[2];
274 	des_block ivec;
275 	int status;
276 	int len;
277 	rpc_inline_t *ixdr;
278 
279 	/*
280 	 * Figure out the "time", accounting for any time difference
281 	 * with the server if necessary.
282 	 */
283 	(void)gettimeofday(&ad->ad_timestamp, NULL);
284 	ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec;
285 	ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec;
286 	while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) {
287 		ad->ad_timestamp.tv_usec -= USEC_PER_SEC;
288 		ad->ad_timestamp.tv_sec++;
289 	}
290 
291 	/*
292 	 * XDR the timestamp and possibly some other things, then
293 	 * encrypt them.
294 	 */
295 	ixdr = (rpc_inline_t *)cryptbuf;
296 	IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec);
297 	IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec);
298 	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
299 		IXDR_PUT_U_INT32(ixdr, ad->ad_window);
300 		IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1);
301 		ivec.key.high = ivec.key.low = 0;
302 		status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,
303 			(u_int) 2 * sizeof (des_block),
304 			DES_ENCRYPT | DES_HW, (char *)&ivec);
305 	} else {
306 		status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,
307 			(u_int) sizeof (des_block),
308 			DES_ENCRYPT | DES_HW);
309 	}
310 	if (DES_FAILED(status)) {
311 		syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
312 		return (FALSE);
313 	}
314 	ad->ad_verf.adv_xtimestamp = cryptbuf[0];
315 	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
316 		ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high;
317 		ad->ad_verf.adv_winverf = cryptbuf[1].key.low;
318 	} else {
319 		ad->ad_cred.adc_nickname = ad->ad_nickname;
320 		ad->ad_verf.adv_winverf = 0;
321 	}
322 
323 	/*
324 	 * Serialize the credential and verifier into opaque
325 	 * authentication data.
326 	 */
327 	if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
328 		len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen);
329 	} else {
330 		len = (1 + 1)*BYTES_PER_XDR_UNIT;
331 	}
332 
333 	if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
334 		IXDR_PUT_INT32(ixdr, AUTH_DES);
335 		IXDR_PUT_INT32(ixdr, len);
336 	} else {
337 		ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor));
338 		ATTEMPT(xdr_putint32(xdrs, &len));
339 	}
340 	ATTEMPT(xdr_authdes_cred(xdrs, cred));
341 
342 	len = (2 + 1)*BYTES_PER_XDR_UNIT;
343 	if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
344 		IXDR_PUT_INT32(ixdr, AUTH_DES);
345 		IXDR_PUT_INT32(ixdr, len);
346 	} else {
347 		ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor));
348 		ATTEMPT(xdr_putint32(xdrs, &len));
349 	}
350 	ATTEMPT(xdr_authdes_verf(xdrs, verf));
351 	return (TRUE);
352 }
353 
354 
355 /*
356  * 3. Validate
357  */
358 static bool_t
authdes_validate(AUTH * auth,struct opaque_auth * rverf)359 authdes_validate(AUTH *auth, struct opaque_auth *rverf)
360 {
361 /* LINTED pointer alignment */
362 	struct ad_private *ad = AUTH_PRIVATE(auth);
363 	struct authdes_verf verf;
364 	int status;
365 	uint32_t *ixdr;
366 	des_block buf;
367 
368 	if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) {
369 		return (FALSE);
370 	}
371 /* LINTED pointer alignment */
372 	ixdr = (uint32_t *)rverf->oa_base;
373 	buf.key.high = (uint32_t)*ixdr++;
374 	buf.key.low = (uint32_t)*ixdr++;
375 	verf.adv_int_u = (uint32_t)*ixdr++;
376 
377 	/*
378 	 * Decrypt the timestamp
379 	 */
380 	status = ecb_crypt((char *)&auth->ah_key, (char *)&buf,
381 		(u_int)sizeof (des_block), DES_DECRYPT | DES_HW);
382 
383 	if (DES_FAILED(status)) {
384 		syslog(LOG_ERR, "authdes_validate: DES decryption failure");
385 		return (FALSE);
386 	}
387 
388 	/*
389 	 * xdr the decrypted timestamp
390 	 */
391 /* LINTED pointer alignment */
392 	ixdr = (uint32_t *)buf.c;
393 	verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1;
394 	verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr);
395 
396 	/*
397 	 * validate
398 	 */
399 	if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
400 		 sizeof(struct timeval)) != 0) {
401 		syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
402 		return (FALSE);
403 	}
404 
405 	/*
406 	 * We have a nickname now, let's use it
407 	 */
408 	ad->ad_nickname = verf.adv_nickname;
409 	ad->ad_cred.adc_namekind = ADN_NICKNAME;
410 	return (TRUE);
411 }
412 
413 /*
414  * 4. Refresh
415  */
416 /*ARGSUSED*/
417 static bool_t
authdes_refresh(AUTH * auth,void * dummy __unused)418 authdes_refresh(AUTH *auth, void *dummy __unused)
419 {
420 /* LINTED pointer alignment */
421 	struct ad_private *ad = AUTH_PRIVATE(auth);
422 	struct authdes_cred *cred = &ad->ad_cred;
423 	int		ok;
424 	netobj		pkey;
425 
426 	if (ad->ad_dosync) {
427                 ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
428 		    ad->ad_timehost, &(ad->ad_uaddr),
429 		    &(ad->ad_netid));
430 		if (! ok) {
431 			/*
432 			 * Hope the clocks are synced!
433 			 */
434 			ad->ad_dosync = 0;
435 			syslog(LOG_DEBUG,
436 			    "authdes_refresh: unable to synchronize clock");
437 		 }
438 	}
439 	ad->ad_xkey = auth->ah_key;
440 	pkey.n_bytes = (char *)(ad->ad_pkey);
441 	pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1;
442 	if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) {
443 		syslog(LOG_INFO,
444 		    "authdes_refresh: keyserv(1m) is unable to encrypt session key");
445 		return (FALSE);
446 	}
447 	cred->adc_fullname.key = ad->ad_xkey;
448 	cred->adc_namekind = ADN_FULLNAME;
449 	cred->adc_fullname.name = ad->ad_fullname;
450 	return (TRUE);
451 }
452 
453 
454 /*
455  * 5. Destroy
456  */
457 static void
authdes_destroy(AUTH * auth)458 authdes_destroy(AUTH *auth)
459 {
460 /* LINTED pointer alignment */
461 	struct ad_private *ad = AUTH_PRIVATE(auth);
462 
463 	FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
464 	FREE(ad->ad_servername, ad->ad_servernamelen + 1);
465 	if (ad->ad_timehost)
466 		FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
467 	if (ad->ad_netid)
468 		FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
469 	if (ad->ad_uaddr)
470 		FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
471 	FREE(ad, sizeof (struct ad_private));
472 	FREE(auth, sizeof(AUTH));
473 }
474 
475 static struct auth_ops *
authdes_ops(void)476 authdes_ops(void)
477 {
478 	static struct auth_ops ops;
479 
480 	/* VARIABLES PROTECTED BY ops_lock: ops */
481 
482 	mutex_lock(&authdes_ops_lock);
483 	if (ops.ah_nextverf == NULL) {
484 		ops.ah_nextverf = authdes_nextverf;
485 		ops.ah_marshal = authdes_marshal;
486 		ops.ah_validate = authdes_validate;
487 		ops.ah_refresh = authdes_refresh;
488 		ops.ah_destroy = authdes_destroy;
489         }
490 	mutex_unlock(&authdes_ops_lock);
491 	return (&ops);
492 }
493