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 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 26 /* All Rights Reserved */ 27 /* 28 * Portions of this source code were derived from Berkeley 29 * 4.3 BSD under license from the Regents of the University of 30 * California. 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 /* 36 * auth_des.c, client-side implementation of DES authentication 37 * 38 */ 39 40 #include "mt.h" 41 #include "rpc_mt.h" 42 #include <rpc/rpc.h> 43 #include <rpc/trace.h> 44 #include <rpc/des_crypt.h> 45 #include <syslog.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <synch.h> 49 #undef NIS 50 #include <rpcsvc/nis.h> 51 52 #define USEC_PER_SEC 1000000 53 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */ 54 55 #define AUTH_PRIVATE(auth) (struct ad_private *)auth->ah_private 56 #define ALLOC(object_type) (object_type *)mem_alloc(sizeof (object_type)) 57 #define FREE(ptr, size) mem_free((char *)(ptr), (int)size) 58 #define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) 59 60 #ifdef _KERNEL 61 #define gettimeofday(tvp, tzp) uniqtime(tvp) /* fake system call */ 62 #endif 63 64 extern bool_t xdr_authdes_cred(XDR *, struct authdes_cred *); 65 extern bool_t xdr_authdes_verf(XDR *, struct authdes_verf *); 66 extern int key_encryptsession_pk(); 67 68 extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, 69 char **, char **); 70 static struct auth_ops *authdes_ops(); 71 static bool_t authdes_refresh(); 72 73 /* 74 * This struct is pointed to by the ah_private field of an "AUTH *" 75 */ 76 struct ad_private { 77 char *ad_fullname; /* client's full name */ 78 uint_t ad_fullnamelen; /* length of name, rounded up */ 79 char *ad_servername; /* server's full name */ 80 size_t ad_servernamelen; /* length of name, rounded up */ 81 uint_t ad_window; /* client specified window */ 82 bool_t ad_dosync; /* synchronize? */ 83 char *ad_timehost; /* remote host to sync with */ 84 struct timeval ad_timediff; /* server's time - client's time */ 85 uint_t ad_nickname; /* server's nickname for client */ 86 struct authdes_cred ad_cred; /* storage for credential */ 87 struct authdes_verf ad_verf; /* storage for verifier */ 88 struct timeval ad_timestamp; /* timestamp sent */ 89 des_block ad_xkey; /* encrypted conversation key */ 90 uchar_t ad_pkey[1024]; /* Servers actual public key */ 91 char *ad_netid; /* Timehost netid */ 92 char *ad_uaddr; /* Timehost uaddr */ 93 nis_server *ad_nis_srvr; /* NIS+ server struct */ 94 }; 95 96 AUTH *authdes_pk_seccreate(const char *, netobj *, uint_t, const char *, 97 const des_block *, nis_server *); 98 99 /* 100 * documented version of authdes_seccreate 101 */ 102 /* 103 * servername: network name of server 104 * win: time to live 105 * timehost: optional hostname to sync with 106 * ckey: optional conversation key to use 107 */ 108 109 AUTH * 110 authdes_seccreate(const char *servername, const uint_t win, 111 const char *timehost, const des_block *ckey) 112 { 113 uchar_t pkey_data[1024]; 114 netobj pkey; 115 AUTH *dummy; 116 117 trace1(TR_authdes_seccreate, 0); 118 if (! getpublickey(servername, (char *)pkey_data)) { 119 syslog(LOG_ERR, 120 "authdes_seccreate: no public key found for %s", 121 servername); 122 123 trace1(TR_authdes_seccreate, 1); 124 return (NULL); 125 } 126 127 pkey.n_bytes = (char *)pkey_data; 128 pkey.n_len = (uint_t)strlen((char *)pkey_data) + 1; 129 dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, 130 ckey, NULL); 131 return (dummy); 132 } 133 134 /* 135 * Slightly modified version of authdes_seccreate which takes the public key 136 * of the server principal as an argument. This spares us a call to 137 * getpublickey() which in the nameserver context can cause a deadlock. 138 */ 139 140 AUTH * 141 authdes_pk_seccreate(const char *servername, netobj *pkey, uint_t window, 142 const char *timehost, const des_block *ckey, nis_server *srvr) 143 { 144 AUTH *auth; 145 struct ad_private *ad; 146 char namebuf[MAXNETNAMELEN+1]; 147 148 /* 149 * Allocate everything now 150 */ 151 trace2(TR_authdes_pk_seccreate, 0, window); 152 auth = ALLOC(AUTH); 153 if (auth == NULL) { 154 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); 155 trace1(TR_authdes_pk_seccreate, 1); 156 return (NULL); 157 } 158 ad = ALLOC(struct ad_private); 159 if (ad == NULL) { 160 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); 161 goto failed; 162 } 163 ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ 164 ad->ad_timehost = NULL; 165 ad->ad_netid = NULL; 166 ad->ad_uaddr = NULL; 167 ad->ad_nis_srvr = NULL; 168 ad->ad_timediff.tv_sec = 0; 169 ad->ad_timediff.tv_usec = 0; 170 memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); 171 if (!getnetname(namebuf)) 172 goto failed; 173 ad->ad_fullnamelen = RNDUP((uint_t)strlen(namebuf)); 174 ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); 175 ad->ad_servernamelen = strlen(servername); 176 ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); 177 178 if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { 179 syslog(LOG_ERR, "authdes_seccreate: out of memory"); 180 goto failed; 181 } 182 if (timehost != NULL) { 183 ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); 184 if (ad->ad_timehost == NULL) { 185 syslog(LOG_ERR, "authdes_seccreate: out of memory"); 186 goto failed; 187 } 188 memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); 189 ad->ad_dosync = TRUE; 190 } else if (srvr != NULL) { 191 ad->ad_nis_srvr = srvr; /* transient */ 192 ad->ad_dosync = TRUE; 193 } else { 194 ad->ad_dosync = FALSE; 195 } 196 memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); 197 memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); 198 ad->ad_window = window; 199 if (ckey == NULL) { 200 if (key_gendes(&auth->ah_key) < 0) { 201 syslog(LOG_ERR, 202 "authdes_seccreate: keyserv(1m) is unable to generate session key"); 203 goto failed; 204 } 205 } else 206 auth->ah_key = *ckey; 207 208 /* 209 * Set up auth handle 210 */ 211 auth->ah_cred.oa_flavor = AUTH_DES; 212 auth->ah_verf.oa_flavor = AUTH_DES; 213 auth->ah_ops = authdes_ops(); 214 auth->ah_private = (caddr_t)ad; 215 216 if (!authdes_refresh(auth, NULL)) { 217 goto failed; 218 } 219 ad->ad_nis_srvr = NULL; /* not needed any longer */ 220 trace1(TR_authdes_pk_seccreate, 1); 221 return (auth); 222 223 failed: 224 if (auth) 225 FREE(auth, sizeof (AUTH)); 226 if (ad) { 227 if (ad->ad_fullname) 228 FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); 229 if (ad->ad_servername) 230 FREE(ad->ad_servername, ad->ad_servernamelen + 1); 231 if (ad->ad_timehost) 232 FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); 233 if (ad->ad_netid) 234 FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); 235 if (ad->ad_uaddr) 236 FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); 237 FREE(ad, sizeof (struct ad_private)); 238 } 239 trace1(TR_authdes_pk_seccreate, 1); 240 return (NULL); 241 } 242 243 /* 244 * Implement the five authentication operations 245 */ 246 247 /* 248 * 1. Next Verifier 249 */ 250 /*ARGSUSED*/ 251 static void 252 authdes_nextverf(AUTH *auth) 253 { 254 trace1(TR_authdes_nextverf, 0); 255 trace1(TR_authdes_nextverf, 1); 256 /* what the heck am I supposed to do??? */ 257 } 258 259 260 /* 261 * 2. Marshal 262 */ 263 static bool_t 264 authdes_marshal(AUTH *auth, XDR *xdrs) 265 { 266 /* LINTED pointer alignment */ 267 struct ad_private *ad = AUTH_PRIVATE(auth); 268 struct authdes_cred *cred = &ad->ad_cred; 269 struct authdes_verf *verf = &ad->ad_verf; 270 des_block cryptbuf[2]; 271 des_block ivec; 272 int status; 273 int len; 274 rpc_inline_t *ixdr; 275 276 /* 277 * Figure out the "time", accounting for any time difference 278 * with the server if necessary. 279 */ 280 trace1(TR_authdes_marshal, 0); 281 (void) gettimeofday(&ad->ad_timestamp, (struct timezone *)NULL); 282 ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; 283 ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; 284 while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { 285 ad->ad_timestamp.tv_usec -= USEC_PER_SEC; 286 ad->ad_timestamp.tv_sec++; 287 } 288 289 /* 290 * XDR the timestamp and possibly some other things, then 291 * encrypt them. 292 */ 293 ixdr = (rpc_inline_t *)cryptbuf; 294 IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); 295 IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); 296 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 297 IXDR_PUT_U_INT32(ixdr, ad->ad_window); 298 IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); 299 ivec.key.high = ivec.key.low = 0; 300 status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, 301 2 * sizeof (des_block), 302 DES_ENCRYPT | DES_HW, (char *)&ivec); 303 } else { 304 status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, 305 sizeof (des_block), 306 DES_ENCRYPT | DES_HW); 307 } 308 if (DES_FAILED(status)) { 309 syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); 310 trace1(TR_authdes_marshal, 1); 311 return (FALSE); 312 } 313 ad->ad_verf.adv_xtimestamp = cryptbuf[0]; 314 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 315 ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; 316 ad->ad_verf.adv_winverf = cryptbuf[1].key.low; 317 } else { 318 ad->ad_cred.adc_nickname = ad->ad_nickname; 319 ad->ad_verf.adv_winverf = 0; 320 } 321 322 /* 323 * Serialize the credential and verifier into opaque 324 * authentication data. 325 */ 326 if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { 327 len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); 328 } else { 329 len = (1 + 1)*BYTES_PER_XDR_UNIT; 330 } 331 332 if (ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT)) { 333 IXDR_PUT_INT32(ixdr, AUTH_DES); 334 IXDR_PUT_INT32(ixdr, len); 335 } else { 336 ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); 337 ATTEMPT(xdr_putint32(xdrs, &len)); 338 } 339 ATTEMPT(xdr_authdes_cred(xdrs, cred)); 340 341 len = (2 + 1)*BYTES_PER_XDR_UNIT; 342 if (ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT)) { 343 IXDR_PUT_INT32(ixdr, AUTH_DES); 344 IXDR_PUT_INT32(ixdr, len); 345 } else { 346 ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); 347 ATTEMPT(xdr_putint32(xdrs, &len)); 348 } 349 ATTEMPT(xdr_authdes_verf(xdrs, verf)); 350 trace1(TR_authdes_marshal, 1); 351 return (TRUE); 352 } 353 354 355 /* 356 * 3. Validate 357 */ 358 static bool_t 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 trace1(TR_authdes_validate, 0); 369 if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { 370 trace1(TR_authdes_validate, 1); 371 return (FALSE); 372 } 373 /* LINTED pointer alignment */ 374 ixdr = (uint32_t *)rverf->oa_base; 375 buf.key.high = (uint32_t)*ixdr++; 376 buf.key.low = (uint32_t)*ixdr++; 377 verf.adv_int_u = (uint32_t)*ixdr++; 378 379 /* 380 * Decrypt the timestamp 381 */ 382 status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, 383 sizeof (des_block), DES_DECRYPT | DES_HW); 384 385 if (DES_FAILED(status)) { 386 syslog(LOG_ERR, "authdes_validate: DES decryption failure"); 387 trace1(TR_authdes_validate, 1); 388 return (FALSE); 389 } 390 391 /* 392 * xdr the decrypted timestamp 393 */ 394 /* LINTED pointer alignment */ 395 ixdr = (uint32_t *)buf.c; 396 verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; 397 verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); 398 399 /* 400 * validate 401 */ 402 if (memcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, 403 sizeof (struct timeval)) != 0) { 404 syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); 405 trace1(TR_authdes_validate, 1); 406 return (FALSE); 407 } 408 409 /* 410 * We have a nickname now, let's use it 411 */ 412 ad->ad_nickname = verf.adv_nickname; 413 ad->ad_cred.adc_namekind = ADN_NICKNAME; 414 trace1(TR_authdes_validate, 1); 415 return (TRUE); 416 } 417 418 /* 419 * 4. Refresh 420 */ 421 /*ARGSUSED*/ 422 static bool_t 423 authdes_refresh(AUTH *auth, void *dummy) 424 { 425 /* LINTED pointer alignment */ 426 struct ad_private *ad = AUTH_PRIVATE(auth); 427 struct authdes_cred *cred = &ad->ad_cred; 428 int ok; 429 netobj pkey; 430 431 trace1(TR_authdes_refresh, 0); 432 433 if (ad->ad_dosync) { 434 ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, 435 ad->ad_timehost, &(ad->ad_uaddr), 436 &(ad->ad_netid)); 437 if (! ok) { 438 /* 439 * Hope the clocks are synced! 440 */ 441 ad->ad_dosync = 0; 442 syslog(LOG_DEBUG, 443 "authdes_refresh: unable to synchronize clock"); 444 } 445 } 446 ad->ad_xkey = auth->ah_key; 447 pkey.n_bytes = (char *)(ad->ad_pkey); 448 pkey.n_len = (uint_t)strlen((char *)ad->ad_pkey) + 1; 449 if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { 450 syslog(LOG_INFO, 451 "authdes_refresh: keyserv(1m) is unable to encrypt session key"); 452 trace1(TR_authdes_refresh, 1); 453 return (FALSE); 454 } 455 cred->adc_fullname.key = ad->ad_xkey; 456 cred->adc_namekind = ADN_FULLNAME; 457 cred->adc_fullname.name = ad->ad_fullname; 458 trace1(TR_authdes_refresh, 1); 459 return (TRUE); 460 } 461 462 463 /* 464 * 5. Destroy 465 */ 466 static void 467 authdes_destroy(AUTH *auth) 468 { 469 /* LINTED pointer alignment */ 470 struct ad_private *ad = AUTH_PRIVATE(auth); 471 472 trace1(TR_authdes_destroy, 0); 473 FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); 474 FREE(ad->ad_servername, ad->ad_servernamelen + 1); 475 if (ad->ad_timehost) 476 FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); 477 if (ad->ad_netid) 478 FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); 479 if (ad->ad_uaddr) 480 FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); 481 FREE(ad, sizeof (struct ad_private)); 482 FREE(auth, sizeof (AUTH)); 483 trace1(TR_authdes_destroy, 1); 484 } 485 486 static struct auth_ops * 487 authdes_ops(void) 488 { 489 static struct auth_ops ops; 490 extern mutex_t ops_lock; 491 492 /* VARIABLES PROTECTED BY ops_lock: ops */ 493 494 trace1(TR_authdes_ops, 0); 495 mutex_lock(&ops_lock); 496 if (ops.ah_nextverf == NULL) { 497 ops.ah_nextverf = authdes_nextverf; 498 ops.ah_marshal = authdes_marshal; 499 ops.ah_validate = authdes_validate; 500 ops.ah_refresh = authdes_refresh; 501 ops.ah_destroy = authdes_destroy; 502 } 503 mutex_unlock(&ops_lock); 504 trace1(TR_authdes_ops, 1); 505 return (&ops); 506 } 507