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) 58 static 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 71 extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); 72 extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); 73 extern int key_encryptsession_pk(); 74 75 extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, 76 char **, char **); 77 78 /* 79 * DES authenticator operations vector 80 */ 81 static void authdes_nextverf(AUTH *); 82 static bool_t authdes_marshal(AUTH *, XDR *); 83 static bool_t authdes_validate(AUTH *, struct opaque_auth *); 84 static bool_t authdes_refresh(AUTH *, void *); 85 static void authdes_destroy(AUTH *); 86 87 static struct auth_ops *authdes_ops(void); 88 89 /* 90 * This struct is pointed to by the ah_private field of an "AUTH *" 91 */ 92 struct 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 113 AUTH *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 126 AUTH * 127 authdes_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 */ 153 AUTH * 154 authdes_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 234 failed: 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*/ 262 static void 263 authdes_nextverf(AUTH *auth) 264 { 265 /* what the heck am I supposed to do??? */ 266 } 267 268 269 /* 270 * 2. Marshal 271 */ 272 static bool_t 273 authdes_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, (struct timezone *)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 */ 364 static bool_t 365 authdes_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*/ 423 static bool_t 424 authdes_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 */ 463 static void 464 authdes_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 481 static struct auth_ops * 482 authdes_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