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 * 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 * 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 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 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 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 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 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 * 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