1/* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29/* 30 * Copyright (c) 1988 by Sun Microsystems, Inc. 31 */ 32/* 33 * auth_des.c, client-side implementation of DES authentication 34 */ 35 36#include "namespace.h" 37#include "reentrant.h" 38#include <err.h> 39#include <errno.h> 40#include <string.h> 41#include <stdlib.h> 42#include <unistd.h> 43#include <sys/cdefs.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#if defined(LIBC_SCCS) && !defined(lint) 58static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI"; 59#endif 60#include <sys/cdefs.h> 61__FBSDID("$FreeBSD$"); 62 63#define USEC_PER_SEC 1000000 64#define RTIME_TIMEOUT 5 /* seconds to wait for sync */ 65 66#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private 67#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type)) 68#define FREE(ptr, size) mem_free((char *)(ptr), (int) size) 69#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) 70 71extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); 72extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); 73extern int key_encryptsession_pk(); 74 75extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, 76 char **, char **); 77 78/* 79 * DES authenticator operations vector 80 */ 81static void authdes_nextverf(AUTH *); 82static bool_t authdes_marshal(AUTH *, XDR *); 83static bool_t authdes_validate(AUTH *, struct opaque_auth *); 84static bool_t authdes_refresh(AUTH *, void *); 85static void authdes_destroy(AUTH *); 86 87static struct auth_ops *authdes_ops(void); 88 89/* 90 * This struct is pointed to by the ah_private field of an "AUTH *" 91 */ 92struct ad_private { 93 char *ad_fullname; /* client's full name */ 94 u_int ad_fullnamelen; /* length of name, rounded up */ 95 char *ad_servername; /* server's full name */ 96 u_int ad_servernamelen; /* length of name, rounded up */ 97 u_int ad_window; /* client specified window */ 98 bool_t ad_dosync; /* synchronize? */ 99 struct netbuf ad_syncaddr; /* remote host to synch with */ 100 char *ad_timehost; /* remote host to synch with */ 101 struct timeval ad_timediff; /* server's time - client's time */ 102 u_int ad_nickname; /* server's nickname for client */ 103 struct authdes_cred ad_cred; /* storage for credential */ 104 struct authdes_verf ad_verf; /* storage for verifier */ 105 struct timeval ad_timestamp; /* timestamp sent */ 106 des_block ad_xkey; /* encrypted conversation key */ 107 u_char ad_pkey[1024]; /* Server's actual public key */ 108 char *ad_netid; /* Timehost netid */ 109 char *ad_uaddr; /* Timehost uaddr */ 110 nis_server *ad_nis_srvr; /* NIS+ server struct */ 111}; 112 113AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *, 114 const des_block *, nis_server *); 115 116/* 117 * documented version of authdes_seccreate 118 */ 119/* 120 servername: network name of server 121 win: time to live 122 timehost: optional hostname to sync with 123 ckey: optional conversation key to use 124*/ 125 126AUTH * 127authdes_seccreate(const char *servername, const u_int win, 128 const char *timehost, const des_block *ckey) 129{ 130 u_char pkey_data[1024]; 131 netobj pkey; 132 AUTH *dummy; 133 134 if (! getpublickey(servername, (char *) pkey_data)) { 135 syslog(LOG_ERR, 136 "authdes_seccreate: no public key found for %s", 137 servername); 138 return (NULL); 139 } 140 141 pkey.n_bytes = (char *) pkey_data; 142 pkey.n_len = (u_int)strlen((char *)pkey_data) + 1; 143 dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, 144 ckey, NULL); 145 return (dummy); 146} 147 148/* 149 * Slightly modified version of authdessec_create which takes the public key 150 * of the server principal as an argument. This spares us a call to 151 * getpublickey() which in the nameserver context can cause a deadlock. 152 */ 153AUTH * 154authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window, 155 const char *timehost, const des_block *ckey, nis_server *srvr) 156{ 157 AUTH *auth; 158 struct ad_private *ad; 159 char namebuf[MAXNETNAMELEN+1]; 160 161 /* 162 * Allocate everything now 163 */ 164 auth = ALLOC(AUTH); 165 if (auth == NULL) { 166 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); 167 return (NULL); 168 } 169 ad = ALLOC(struct ad_private); 170 if (ad == NULL) { 171 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); 172 goto failed; 173 } 174 ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ 175 ad->ad_timehost = NULL; 176 ad->ad_netid = NULL; 177 ad->ad_uaddr = NULL; 178 ad->ad_nis_srvr = NULL; 179 ad->ad_timediff.tv_sec = 0; 180 ad->ad_timediff.tv_usec = 0; 181 memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); 182 if (!getnetname(namebuf)) 183 goto failed; 184 ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf)); 185 ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); 186 ad->ad_servernamelen = strlen(servername); 187 ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); 188 189 if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { 190 syslog(LOG_ERR, "authdes_seccreate: out of memory"); 191 goto failed; 192 } 193 if (timehost != NULL) { 194 ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); 195 if (ad->ad_timehost == NULL) { 196 syslog(LOG_ERR, "authdes_seccreate: out of memory"); 197 goto failed; 198 } 199 memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); 200 ad->ad_dosync = TRUE; 201 } else if (srvr != NULL) { 202 ad->ad_nis_srvr = srvr; /* transient */ 203 ad->ad_dosync = TRUE; 204 } else { 205 ad->ad_dosync = FALSE; 206 } 207 memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); 208 memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); 209 ad->ad_window = window; 210 if (ckey == NULL) { 211 if (key_gendes(&auth->ah_key) < 0) { 212 syslog(LOG_ERR, 213 "authdes_seccreate: keyserv(1m) is unable to generate session key"); 214 goto failed; 215 } 216 } else { 217 auth->ah_key = *ckey; 218 } 219 220 /* 221 * Set up auth handle 222 */ 223 auth->ah_cred.oa_flavor = AUTH_DES; 224 auth->ah_verf.oa_flavor = AUTH_DES; 225 auth->ah_ops = authdes_ops(); 226 auth->ah_private = (caddr_t)ad; 227 228 if (!authdes_refresh(auth, NULL)) { 229 goto failed; 230 } 231 ad->ad_nis_srvr = NULL; /* not needed any longer */ 232 return (auth); 233 234failed: 235 if (auth) 236 FREE(auth, sizeof (AUTH)); 237 if (ad) { 238 if (ad->ad_fullname) 239 FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); 240 if (ad->ad_servername) 241 FREE(ad->ad_servername, ad->ad_servernamelen + 1); 242 if (ad->ad_timehost) 243 FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); 244 if (ad->ad_netid) 245 FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); 246 if (ad->ad_uaddr) 247 FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); 248 FREE(ad, sizeof (struct ad_private)); 249 } 250 return (NULL); 251} 252 253/* 254 * Implement the five authentication operations 255 */ 256 257 258/* 259 * 1. Next Verifier 260 */ 261/*ARGSUSED*/ 262static void 263authdes_nextverf(AUTH *auth) 264{ 265 /* what the heck am I supposed to do??? */ 266} 267 268 269/* 270 * 2. Marshal 271 */ 272static bool_t 273authdes_marshal(AUTH *auth, XDR *xdrs) 274{ 275/* LINTED pointer alignment */ 276 struct ad_private *ad = AUTH_PRIVATE(auth); 277 struct authdes_cred *cred = &ad->ad_cred; 278 struct authdes_verf *verf = &ad->ad_verf; 279 des_block cryptbuf[2]; 280 des_block ivec; 281 int status; 282 int len; 283 rpc_inline_t *ixdr; 284 285 /* 286 * Figure out the "time", accounting for any time difference 287 * with the server if necessary. 288 */ 289 (void)gettimeofday(&ad->ad_timestamp, NULL); 290 ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; 291 ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; 292 while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { 293 ad->ad_timestamp.tv_usec -= USEC_PER_SEC; 294 ad->ad_timestamp.tv_sec++; 295 } 296 297 /* 298 * XDR the timestamp and possibly some other things, then 299 * encrypt them. 300 */ 301 ixdr = (rpc_inline_t *)cryptbuf; 302 IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); 303 IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); 304 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 305 IXDR_PUT_U_INT32(ixdr, ad->ad_window); 306 IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); 307 ivec.key.high = ivec.key.low = 0; 308 status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, 309 (u_int) 2 * sizeof (des_block), 310 DES_ENCRYPT | DES_HW, (char *)&ivec); 311 } else { 312 status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, 313 (u_int) sizeof (des_block), 314 DES_ENCRYPT | DES_HW); 315 } 316 if (DES_FAILED(status)) { 317 syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); 318 return (FALSE); 319 } 320 ad->ad_verf.adv_xtimestamp = cryptbuf[0]; 321 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 322 ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; 323 ad->ad_verf.adv_winverf = cryptbuf[1].key.low; 324 } else { 325 ad->ad_cred.adc_nickname = ad->ad_nickname; 326 ad->ad_verf.adv_winverf = 0; 327 } 328 329 /* 330 * Serialize the credential and verifier into opaque 331 * authentication data. 332 */ 333 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 334 len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); 335 } else { 336 len = (1 + 1)*BYTES_PER_XDR_UNIT; 337 } 338 339 if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { 340 IXDR_PUT_INT32(ixdr, AUTH_DES); 341 IXDR_PUT_INT32(ixdr, len); 342 } else { 343 ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); 344 ATTEMPT(xdr_putint32(xdrs, &len)); 345 } 346 ATTEMPT(xdr_authdes_cred(xdrs, cred)); 347 348 len = (2 + 1)*BYTES_PER_XDR_UNIT; 349 if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { 350 IXDR_PUT_INT32(ixdr, AUTH_DES); 351 IXDR_PUT_INT32(ixdr, len); 352 } else { 353 ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); 354 ATTEMPT(xdr_putint32(xdrs, &len)); 355 } 356 ATTEMPT(xdr_authdes_verf(xdrs, verf)); 357 return (TRUE); 358} 359 360 361/* 362 * 3. Validate 363 */ 364static bool_t 365authdes_validate(AUTH *auth, struct opaque_auth *rverf) 366{ 367/* LINTED pointer alignment */ 368 struct ad_private *ad = AUTH_PRIVATE(auth); 369 struct authdes_verf verf; 370 int status; 371 uint32_t *ixdr; 372 des_block buf; 373 374 if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { 375 return (FALSE); 376 } 377/* LINTED pointer alignment */ 378 ixdr = (uint32_t *)rverf->oa_base; 379 buf.key.high = (uint32_t)*ixdr++; 380 buf.key.low = (uint32_t)*ixdr++; 381 verf.adv_int_u = (uint32_t)*ixdr++; 382 383 /* 384 * Decrypt the timestamp 385 */ 386 status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, 387 (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); 388 389 if (DES_FAILED(status)) { 390 syslog(LOG_ERR, "authdes_validate: DES decryption failure"); 391 return (FALSE); 392 } 393 394 /* 395 * xdr the decrypted timestamp 396 */ 397/* LINTED pointer alignment */ 398 ixdr = (uint32_t *)buf.c; 399 verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; 400 verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); 401 402 /* 403 * validate 404 */ 405 if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, 406 sizeof(struct timeval)) != 0) { 407 syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); 408 return (FALSE); 409 } 410 411 /* 412 * We have a nickname now, let's use it 413 */ 414 ad->ad_nickname = verf.adv_nickname; 415 ad->ad_cred.adc_namekind = ADN_NICKNAME; 416 return (TRUE); 417} 418 419/* 420 * 4. Refresh 421 */ 422/*ARGSUSED*/ 423static bool_t 424authdes_refresh(AUTH *auth, void *dummy) 425{ 426/* LINTED pointer alignment */ 427 struct ad_private *ad = AUTH_PRIVATE(auth); 428 struct authdes_cred *cred = &ad->ad_cred; 429 int ok; 430 netobj pkey; 431 432 if (ad->ad_dosync) { 433 ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, 434 ad->ad_timehost, &(ad->ad_uaddr), 435 &(ad->ad_netid)); 436 if (! ok) { 437 /* 438 * Hope the clocks are synced! 439 */ 440 ad->ad_dosync = 0; 441 syslog(LOG_DEBUG, 442 "authdes_refresh: unable to synchronize clock"); 443 } 444 } 445 ad->ad_xkey = auth->ah_key; 446 pkey.n_bytes = (char *)(ad->ad_pkey); 447 pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; 448 if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { 449 syslog(LOG_INFO, 450 "authdes_refresh: keyserv(1m) is unable to encrypt session key"); 451 return (FALSE); 452 } 453 cred->adc_fullname.key = ad->ad_xkey; 454 cred->adc_namekind = ADN_FULLNAME; 455 cred->adc_fullname.name = ad->ad_fullname; 456 return (TRUE); 457} 458 459 460/* 461 * 5. Destroy 462 */ 463static void 464authdes_destroy(AUTH *auth) 465{ 466/* LINTED pointer alignment */ 467 struct ad_private *ad = AUTH_PRIVATE(auth); 468 469 FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); 470 FREE(ad->ad_servername, ad->ad_servernamelen + 1); 471 if (ad->ad_timehost) 472 FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); 473 if (ad->ad_netid) 474 FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); 475 if (ad->ad_uaddr) 476 FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); 477 FREE(ad, sizeof (struct ad_private)); 478 FREE(auth, sizeof(AUTH)); 479} 480 481static struct auth_ops * 482authdes_ops(void) 483{ 484 static struct auth_ops ops; 485 486 /* VARIABLES PROTECTED BY ops_lock: ops */ 487 488 mutex_lock(&authdes_ops_lock); 489 if (ops.ah_nextverf == NULL) { 490 ops.ah_nextverf = authdes_nextverf; 491 ops.ah_marshal = authdes_marshal; 492 ops.ah_validate = authdes_validate; 493 ops.ah_refresh = authdes_refresh; 494 ops.ah_destroy = authdes_destroy; 495 } 496 mutex_unlock(&authdes_ops_lock); 497 return (&ops); 498} 499