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
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.
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]
24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
35 #pragma ident "%Z%%M% %I% %E% SMI"
38 * auth_des.c, client-side implementation of DES authentication
45 #include <rpc/des_crypt.h>
51 #include <rpcsvc/nis.h>
53 #define USEC_PER_SEC 1000000
54 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */
56 extern bool_t
xdr_authdes_cred(XDR
*, struct authdes_cred
*);
57 extern bool_t
xdr_authdes_verf(XDR
*, struct authdes_verf
*);
58 extern int key_encryptsession_pk(const char *, netobj
*, des_block
*);
60 extern bool_t
__rpc_get_time_offset(struct timeval
*, nis_server
*, char *,
62 static struct auth_ops
*authdes_ops(void);
63 static bool_t
authdes_refresh(AUTH
*, void *);
66 * This struct is pointed to by the ah_private field of an "AUTH *"
69 char *ad_fullname
; /* client's full name */
70 uint_t ad_fullnamelen
; /* length of name, rounded up */
71 char *ad_servername
; /* server's full name */
72 size_t ad_servernamelen
; /* length of name, rounded up */
73 uint_t ad_window
; /* client specified window */
74 bool_t ad_dosync
; /* synchronize? */
75 char *ad_timehost
; /* remote host to sync with */
76 struct timeval ad_timediff
; /* server's time - client's time */
77 uint_t ad_nickname
; /* server's nickname for client */
78 struct authdes_cred ad_cred
; /* storage for credential */
79 struct authdes_verf ad_verf
; /* storage for verifier */
80 struct timeval ad_timestamp
; /* timestamp sent */
81 des_block ad_xkey
; /* encrypted conversation key */
82 uchar_t ad_pkey
[1024]; /* Servers actual public key */
83 char *ad_netid
; /* Timehost netid */
84 char *ad_uaddr
; /* Timehost uaddr */
85 nis_server
*ad_nis_srvr
; /* NIS+ server struct */
88 extern AUTH
*authdes_pk_seccreate(const char *, netobj
*, uint_t
, const char *,
89 const des_block
*, nis_server
*);
92 * documented version of authdes_seccreate
95 * servername: network name of server
97 * timehost: optional hostname to sync with
98 * ckey: optional conversation key to use
102 authdes_seccreate(const char *servername
, const uint_t win
,
103 const char *timehost
, const des_block
*ckey
)
105 uchar_t pkey_data
[1024];
108 if (!getpublickey(servername
, (char *)pkey_data
)) {
110 "authdes_seccreate: no public key found for %s",
116 pkey
.n_bytes
= (char *)pkey_data
;
117 pkey
.n_len
= (uint_t
)strlen((char *)pkey_data
) + 1;
118 return (authdes_pk_seccreate(servername
, &pkey
, win
, timehost
,
123 * Slightly modified version of authdes_seccreate which takes the public key
124 * of the server principal as an argument. This spares us a call to
125 * getpublickey() which in the nameserver context can cause a deadlock.
129 authdes_pk_seccreate(const char *servername
, netobj
*pkey
, uint_t window
,
130 const char *timehost
, const des_block
*ckey
, nis_server
*srvr
)
133 struct ad_private
*ad
;
134 char namebuf
[MAXNETNAMELEN
+1];
137 * Allocate everything now
139 auth
= malloc(sizeof (AUTH
));
141 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
144 ad
= malloc(sizeof (struct ad_private
));
146 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
149 ad
->ad_fullname
= ad
->ad_servername
= NULL
; /* Sanity reasons */
150 ad
->ad_timehost
= NULL
;
153 ad
->ad_nis_srvr
= NULL
;
154 ad
->ad_timediff
.tv_sec
= 0;
155 ad
->ad_timediff
.tv_usec
= 0;
156 (void) memcpy(ad
->ad_pkey
, pkey
->n_bytes
, pkey
->n_len
);
157 if (!getnetname(namebuf
))
159 ad
->ad_fullnamelen
= RNDUP((uint_t
)strlen(namebuf
));
160 ad
->ad_fullname
= malloc(ad
->ad_fullnamelen
+ 1);
161 ad
->ad_servernamelen
= strlen(servername
);
162 ad
->ad_servername
= malloc(ad
->ad_servernamelen
+ 1);
164 if (ad
->ad_fullname
== NULL
|| ad
->ad_servername
== NULL
) {
165 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
168 if (timehost
!= NULL
) {
169 ad
->ad_timehost
= malloc(strlen(timehost
) + 1);
170 if (ad
->ad_timehost
== NULL
) {
171 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
174 (void) memcpy(ad
->ad_timehost
, timehost
, strlen(timehost
) + 1);
175 ad
->ad_dosync
= TRUE
;
176 } else if (srvr
!= NULL
) {
177 ad
->ad_nis_srvr
= srvr
; /* transient */
178 ad
->ad_dosync
= TRUE
;
180 ad
->ad_dosync
= FALSE
;
182 (void) memcpy(ad
->ad_fullname
, namebuf
, ad
->ad_fullnamelen
+ 1);
183 (void) memcpy(ad
->ad_servername
, servername
, ad
->ad_servernamelen
+ 1);
184 ad
->ad_window
= window
;
186 if (key_gendes(&auth
->ah_key
) < 0) {
188 "authdes_seccreate: keyserv(1m) is unable to generate session key");
192 auth
->ah_key
= *ckey
;
197 auth
->ah_cred
.oa_flavor
= AUTH_DES
;
198 auth
->ah_verf
.oa_flavor
= AUTH_DES
;
199 auth
->ah_ops
= authdes_ops();
200 auth
->ah_private
= (caddr_t
)ad
;
202 if (!authdes_refresh(auth
, NULL
)) {
205 ad
->ad_nis_srvr
= NULL
; /* not needed any longer */
213 free(ad
->ad_fullname
);
214 if (ad
->ad_servername
)
215 free(ad
->ad_servername
);
217 free(ad
->ad_timehost
);
228 * Implement the five authentication operations
236 authdes_nextverf(AUTH
*auth
)
238 /* what the heck am I supposed to do??? */
246 authdes_marshal(AUTH
*auth
, XDR
*xdrs
)
248 /* LINTED pointer alignment */
249 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
250 struct authdes_cred
*cred
= &ad
->ad_cred
;
251 struct authdes_verf
*verf
= &ad
->ad_verf
;
252 des_block cryptbuf
[2];
259 * Figure out the "time", accounting for any time difference
260 * with the server if necessary.
262 (void) gettimeofday(&ad
->ad_timestamp
, NULL
);
263 ad
->ad_timestamp
.tv_sec
+= ad
->ad_timediff
.tv_sec
;
264 ad
->ad_timestamp
.tv_usec
+= ad
->ad_timediff
.tv_usec
;
265 while (ad
->ad_timestamp
.tv_usec
>= USEC_PER_SEC
) {
266 ad
->ad_timestamp
.tv_usec
-= USEC_PER_SEC
;
267 ad
->ad_timestamp
.tv_sec
++;
271 * XDR the timestamp and possibly some other things, then
274 ixdr
= (rpc_inline_t
*)cryptbuf
;
275 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_sec
);
276 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_usec
);
277 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
278 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
);
279 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
- 1);
280 ivec
.key
.high
= ivec
.key
.low
= 0;
281 status
= cbc_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
282 2 * sizeof (des_block
),
283 DES_ENCRYPT
| DES_HW
, (char *)&ivec
);
285 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
287 DES_ENCRYPT
| DES_HW
);
289 if (DES_FAILED(status
)) {
290 syslog(LOG_ERR
, "authdes_marshal: DES encryption failure");
293 ad
->ad_verf
.adv_xtimestamp
= cryptbuf
[0];
294 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
295 ad
->ad_cred
.adc_fullname
.window
= cryptbuf
[1].key
.high
;
296 ad
->ad_verf
.adv_winverf
= cryptbuf
[1].key
.low
;
298 ad
->ad_cred
.adc_nickname
= ad
->ad_nickname
;
299 ad
->ad_verf
.adv_winverf
= 0;
303 * Serialize the credential and verifier into opaque
304 * authentication data.
306 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
307 len
= ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT
+ ad
->ad_fullnamelen
);
309 len
= (1 + 1)*BYTES_PER_XDR_UNIT
;
312 if (ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
)) {
313 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
314 IXDR_PUT_INT32(ixdr
, len
);
316 if (!xdr_putint32(xdrs
, (int *)&auth
->ah_cred
.oa_flavor
))
318 if (!xdr_putint32(xdrs
, &len
))
321 if (!xdr_authdes_cred(xdrs
, cred
))
324 len
= (2 + 1)*BYTES_PER_XDR_UNIT
;
325 if (ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
)) {
326 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
327 IXDR_PUT_INT32(ixdr
, len
);
329 if (!xdr_putint32(xdrs
, (int *)&auth
->ah_verf
.oa_flavor
))
331 if (!xdr_putint32(xdrs
, &len
))
334 return (xdr_authdes_verf(xdrs
, verf
));
342 authdes_validate(AUTH
*auth
, struct opaque_auth
*rverf
)
344 /* LINTED pointer alignment */
345 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
346 struct authdes_verf verf
;
351 if (rverf
->oa_length
!= (2 + 1) * BYTES_PER_XDR_UNIT
)
353 /* LINTED pointer alignment */
354 ixdr
= (uint32_t *)rverf
->oa_base
;
355 buf
.key
.high
= (uint32_t)*ixdr
++;
356 buf
.key
.low
= (uint32_t)*ixdr
++;
357 verf
.adv_int_u
= (uint32_t)*ixdr
++;
360 * Decrypt the timestamp
362 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)&buf
,
363 sizeof (des_block
), DES_DECRYPT
| DES_HW
);
365 if (DES_FAILED(status
)) {
366 syslog(LOG_ERR
, "authdes_validate: DES decryption failure");
371 * xdr the decrypted timestamp
373 /* LINTED pointer alignment */
374 ixdr
= (uint32_t *)buf
.c
;
375 verf
.adv_timestamp
.tv_sec
= IXDR_GET_INT32(ixdr
) + 1;
376 verf
.adv_timestamp
.tv_usec
= IXDR_GET_INT32(ixdr
);
381 if (memcmp(&ad
->ad_timestamp
, &verf
.adv_timestamp
,
382 sizeof (struct timeval
)) != 0) {
383 syslog(LOG_DEBUG
, "authdes_validate: verifier mismatch");
388 * We have a nickname now, let's use it
390 ad
->ad_nickname
= verf
.adv_nickname
;
391 ad
->ad_cred
.adc_namekind
= ADN_NICKNAME
;
400 authdes_refresh(AUTH
*auth
, void *dummy
)
402 /* LINTED pointer alignment */
403 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
404 struct authdes_cred
*cred
= &ad
->ad_cred
;
409 ok
= __rpc_get_time_offset(&ad
->ad_timediff
, ad
->ad_nis_srvr
,
410 ad
->ad_timehost
, &(ad
->ad_uaddr
),
414 * Hope the clocks are synced!
418 "authdes_refresh: unable to synchronize clock");
421 ad
->ad_xkey
= auth
->ah_key
;
422 pkey
.n_bytes
= (char *)(ad
->ad_pkey
);
423 pkey
.n_len
= (uint_t
)strlen((char *)ad
->ad_pkey
) + 1;
424 if (key_encryptsession_pk(ad
->ad_servername
, &pkey
, &ad
->ad_xkey
) < 0) {
426 "authdes_refresh: keyserv(1m) is unable to encrypt session key");
429 cred
->adc_fullname
.key
= ad
->ad_xkey
;
430 cred
->adc_namekind
= ADN_FULLNAME
;
431 cred
->adc_fullname
.name
= ad
->ad_fullname
;
440 authdes_destroy(AUTH
*auth
)
442 /* LINTED pointer alignment */
443 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
445 free(ad
->ad_fullname
);
446 free(ad
->ad_servername
);
448 free(ad
->ad_timehost
);
457 static struct auth_ops
*
460 static struct auth_ops ops
;
461 extern mutex_t ops_lock
;
463 /* VARIABLES PROTECTED BY ops_lock: ops */
465 (void) mutex_lock(&ops_lock
);
466 if (ops
.ah_nextverf
== NULL
) {
467 ops
.ah_nextverf
= authdes_nextverf
;
468 ops
.ah_marshal
= authdes_marshal
;
469 ops
.ah_validate
= authdes_validate
;
470 ops
.ah_refresh
= authdes_refresh
;
471 ops
.ah_destroy
= authdes_destroy
;
473 (void) mutex_unlock(&ops_lock
);