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
36 * auth_des.c, client-side implementation of DES authentication
43 #include <rpc/des_crypt.h>
48 #include <rpcsvc/nis.h>
50 #define USEC_PER_SEC 1000000
51 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */
53 extern bool_t
xdr_authdes_cred(XDR
*, struct authdes_cred
*);
54 extern bool_t
xdr_authdes_verf(XDR
*, struct authdes_verf
*);
55 extern int key_encryptsession_pk(const char *, netobj
*, des_block
*);
57 extern bool_t
__rpc_get_time_offset(struct timeval
*, nis_server
*, char *,
59 static struct auth_ops
*authdes_ops(void);
60 static bool_t
authdes_refresh(AUTH
*, void *);
63 * This struct is pointed to by the ah_private field of an "AUTH *"
66 char *ad_fullname
; /* client's full name */
67 uint_t ad_fullnamelen
; /* length of name, rounded up */
68 char *ad_servername
; /* server's full name */
69 size_t ad_servernamelen
; /* length of name, rounded up */
70 uint_t ad_window
; /* client specified window */
71 bool_t ad_dosync
; /* synchronize? */
72 char *ad_timehost
; /* remote host to sync with */
73 struct timeval ad_timediff
; /* server's time - client's time */
74 uint_t ad_nickname
; /* server's nickname for client */
75 struct authdes_cred ad_cred
; /* storage for credential */
76 struct authdes_verf ad_verf
; /* storage for verifier */
77 struct timeval ad_timestamp
; /* timestamp sent */
78 des_block ad_xkey
; /* encrypted conversation key */
79 uchar_t ad_pkey
[1024]; /* Servers actual public key */
80 char *ad_netid
; /* Timehost netid */
81 char *ad_uaddr
; /* Timehost uaddr */
82 nis_server
*ad_nis_srvr
; /* NIS+ server struct */
85 extern AUTH
*authdes_pk_seccreate(const char *, netobj
*, uint_t
, const char *,
86 const des_block
*, nis_server
*);
89 * documented version of authdes_seccreate
92 * servername: network name of server
94 * timehost: optional hostname to sync with
95 * ckey: optional conversation key to use
99 authdes_seccreate(const char *servername
, const uint_t win
,
100 const char *timehost
, const des_block
*ckey
)
102 uchar_t pkey_data
[1024];
105 if (!getpublickey(servername
, (char *)pkey_data
)) {
107 "authdes_seccreate: no public key found for %s",
113 pkey
.n_bytes
= (char *)pkey_data
;
114 pkey
.n_len
= (uint_t
)strlen((char *)pkey_data
) + 1;
115 return (authdes_pk_seccreate(servername
, &pkey
, win
, timehost
,
120 * Slightly modified version of authdes_seccreate which takes the public key
121 * of the server principal as an argument. This spares us a call to
122 * getpublickey() which in the nameserver context can cause a deadlock.
126 authdes_pk_seccreate(const char *servername
, netobj
*pkey
, uint_t window
,
127 const char *timehost
, const des_block
*ckey
, nis_server
*srvr
)
130 struct ad_private
*ad
;
131 char namebuf
[MAXNETNAMELEN
+1];
134 * Allocate everything now
136 auth
= malloc(sizeof (AUTH
));
138 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
141 ad
= malloc(sizeof (struct ad_private
));
143 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
146 ad
->ad_fullname
= ad
->ad_servername
= NULL
; /* Sanity reasons */
147 ad
->ad_timehost
= NULL
;
150 ad
->ad_nis_srvr
= NULL
;
151 ad
->ad_timediff
.tv_sec
= 0;
152 ad
->ad_timediff
.tv_usec
= 0;
153 (void) memcpy(ad
->ad_pkey
, pkey
->n_bytes
, pkey
->n_len
);
154 if (!getnetname(namebuf
))
156 ad
->ad_fullnamelen
= RNDUP((uint_t
)strlen(namebuf
));
157 ad
->ad_fullname
= malloc(ad
->ad_fullnamelen
+ 1);
158 ad
->ad_servernamelen
= strlen(servername
);
159 ad
->ad_servername
= malloc(ad
->ad_servernamelen
+ 1);
161 if (ad
->ad_fullname
== NULL
|| ad
->ad_servername
== NULL
) {
162 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
165 if (timehost
!= NULL
) {
166 ad
->ad_timehost
= malloc(strlen(timehost
) + 1);
167 if (ad
->ad_timehost
== NULL
) {
168 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
171 (void) memcpy(ad
->ad_timehost
, timehost
, strlen(timehost
) + 1);
172 ad
->ad_dosync
= TRUE
;
173 } else if (srvr
!= NULL
) {
174 ad
->ad_nis_srvr
= srvr
; /* transient */
175 ad
->ad_dosync
= TRUE
;
177 ad
->ad_dosync
= FALSE
;
179 (void) memcpy(ad
->ad_fullname
, namebuf
, ad
->ad_fullnamelen
+ 1);
180 (void) memcpy(ad
->ad_servername
, servername
, ad
->ad_servernamelen
+ 1);
181 ad
->ad_window
= window
;
183 if (key_gendes(&auth
->ah_key
) < 0) {
185 "authdes_seccreate: keyserv(1m) is unable to generate session key");
189 auth
->ah_key
= *ckey
;
194 auth
->ah_cred
.oa_flavor
= AUTH_DES
;
195 auth
->ah_verf
.oa_flavor
= AUTH_DES
;
196 auth
->ah_ops
= authdes_ops();
197 auth
->ah_private
= (caddr_t
)ad
;
199 if (!authdes_refresh(auth
, NULL
)) {
202 ad
->ad_nis_srvr
= NULL
; /* not needed any longer */
208 free(ad
->ad_fullname
);
209 free(ad
->ad_servername
);
210 free(ad
->ad_timehost
);
219 * Implement the five authentication operations
227 authdes_nextverf(AUTH
*auth
)
229 /* what the heck am I supposed to do??? */
237 authdes_marshal(AUTH
*auth
, XDR
*xdrs
)
239 /* LINTED pointer alignment */
240 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
241 struct authdes_cred
*cred
= &ad
->ad_cred
;
242 struct authdes_verf
*verf
= &ad
->ad_verf
;
243 des_block cryptbuf
[2];
250 * Figure out the "time", accounting for any time difference
251 * with the server if necessary.
253 (void) gettimeofday(&ad
->ad_timestamp
, NULL
);
254 ad
->ad_timestamp
.tv_sec
+= ad
->ad_timediff
.tv_sec
;
255 ad
->ad_timestamp
.tv_usec
+= ad
->ad_timediff
.tv_usec
;
256 while (ad
->ad_timestamp
.tv_usec
>= USEC_PER_SEC
) {
257 ad
->ad_timestamp
.tv_usec
-= USEC_PER_SEC
;
258 ad
->ad_timestamp
.tv_sec
++;
262 * XDR the timestamp and possibly some other things, then
265 ixdr
= (rpc_inline_t
*)cryptbuf
;
266 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_sec
);
267 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_usec
);
268 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
269 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
);
270 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
- 1);
271 ivec
.key
.high
= ivec
.key
.low
= 0;
272 status
= cbc_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
273 2 * sizeof (des_block
),
274 DES_ENCRYPT
| DES_HW
, (char *)&ivec
);
276 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
278 DES_ENCRYPT
| DES_HW
);
280 if (DES_FAILED(status
)) {
281 syslog(LOG_ERR
, "authdes_marshal: DES encryption failure");
284 ad
->ad_verf
.adv_xtimestamp
= cryptbuf
[0];
285 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
286 ad
->ad_cred
.adc_fullname
.window
= cryptbuf
[1].key
.high
;
287 ad
->ad_verf
.adv_winverf
= cryptbuf
[1].key
.low
;
289 ad
->ad_cred
.adc_nickname
= ad
->ad_nickname
;
290 ad
->ad_verf
.adv_winverf
= 0;
294 * Serialize the credential and verifier into opaque
295 * authentication data.
297 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
298 len
= ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT
+ ad
->ad_fullnamelen
);
300 len
= (1 + 1)*BYTES_PER_XDR_UNIT
;
303 if (ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
)) {
304 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
305 IXDR_PUT_INT32(ixdr
, len
);
307 if (!xdr_putint32(xdrs
, (int *)&auth
->ah_cred
.oa_flavor
))
309 if (!xdr_putint32(xdrs
, &len
))
312 if (!xdr_authdes_cred(xdrs
, cred
))
315 len
= (2 + 1)*BYTES_PER_XDR_UNIT
;
316 if (ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
)) {
317 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
318 IXDR_PUT_INT32(ixdr
, len
);
320 if (!xdr_putint32(xdrs
, (int *)&auth
->ah_verf
.oa_flavor
))
322 if (!xdr_putint32(xdrs
, &len
))
325 return (xdr_authdes_verf(xdrs
, verf
));
333 authdes_validate(AUTH
*auth
, struct opaque_auth
*rverf
)
335 /* LINTED pointer alignment */
336 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
337 struct authdes_verf verf
;
342 if (rverf
->oa_length
!= (2 + 1) * BYTES_PER_XDR_UNIT
)
344 /* LINTED pointer alignment */
345 ixdr
= (uint32_t *)rverf
->oa_base
;
346 buf
.key
.high
= (uint32_t)*ixdr
++;
347 buf
.key
.low
= (uint32_t)*ixdr
++;
348 verf
.adv_int_u
= (uint32_t)*ixdr
++;
351 * Decrypt the timestamp
353 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)&buf
,
354 sizeof (des_block
), DES_DECRYPT
| DES_HW
);
356 if (DES_FAILED(status
)) {
357 syslog(LOG_ERR
, "authdes_validate: DES decryption failure");
362 * xdr the decrypted timestamp
364 /* LINTED pointer alignment */
365 ixdr
= (uint32_t *)buf
.c
;
366 verf
.adv_timestamp
.tv_sec
= IXDR_GET_INT32(ixdr
) + 1;
367 verf
.adv_timestamp
.tv_usec
= IXDR_GET_INT32(ixdr
);
372 if (memcmp(&ad
->ad_timestamp
, &verf
.adv_timestamp
,
373 sizeof (struct timeval
)) != 0) {
374 syslog(LOG_DEBUG
, "authdes_validate: verifier mismatch");
379 * We have a nickname now, let's use it
381 ad
->ad_nickname
= verf
.adv_nickname
;
382 ad
->ad_cred
.adc_namekind
= ADN_NICKNAME
;
391 authdes_refresh(AUTH
*auth
, void *dummy
)
393 /* LINTED pointer alignment */
394 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
395 struct authdes_cred
*cred
= &ad
->ad_cred
;
400 ok
= __rpc_get_time_offset(&ad
->ad_timediff
, ad
->ad_nis_srvr
,
401 ad
->ad_timehost
, &(ad
->ad_uaddr
),
405 * Hope the clocks are synced!
409 "authdes_refresh: unable to synchronize clock");
412 ad
->ad_xkey
= auth
->ah_key
;
413 pkey
.n_bytes
= (char *)(ad
->ad_pkey
);
414 pkey
.n_len
= (uint_t
)strlen((char *)ad
->ad_pkey
) + 1;
415 if (key_encryptsession_pk(ad
->ad_servername
, &pkey
, &ad
->ad_xkey
) < 0) {
417 "authdes_refresh: keyserv(1m) is unable to encrypt session key");
420 cred
->adc_fullname
.key
= ad
->ad_xkey
;
421 cred
->adc_namekind
= ADN_FULLNAME
;
422 cred
->adc_fullname
.name
= ad
->ad_fullname
;
431 authdes_destroy(AUTH
*auth
)
433 /* LINTED pointer alignment */
434 struct ad_private
*ad
= (struct ad_private
*)auth
->ah_private
;
436 free(ad
->ad_fullname
);
437 free(ad
->ad_servername
);
438 free(ad
->ad_timehost
);
445 static struct auth_ops
*
448 static struct auth_ops ops
;
449 extern mutex_t ops_lock
;
451 /* VARIABLES PROTECTED BY ops_lock: ops */
453 (void) mutex_lock(&ops_lock
);
454 if (ops
.ah_nextverf
== NULL
) {
455 ops
.ah_nextverf
= authdes_nextverf
;
456 ops
.ah_marshal
= authdes_marshal
;
457 ops
.ah_validate
= authdes_validate
;
458 ops
.ah_refresh
= authdes_refresh
;
459 ops
.ah_destroy
= authdes_destroy
;
461 (void) mutex_unlock(&ops_lock
);