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