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]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
35 #pragma ident "%Z%%M% %I% %E% SMI"
38 * auth_des.c, client-side implementation of DES authentication
41 #include <sys/types.h>
42 #include <sys/t_lock.h>
44 #include <sys/systm.h>
45 #include <sys/socket.h>
46 #include <sys/tiuser.h>
47 #include <sys/errno.h>
48 #include <rpc/des_crypt.h>
49 #include <rpc/types.h>
51 #include <rpc/auth_des.h>
54 #include <rpc/rpc_msg.h>
55 #include <netinet/in.h> /* XXX: just to get htonl() and ntohl() */
56 #include <sys/cmn_err.h>
57 #include <sys/debug.h>
59 #define MILLION 1000000
60 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */
62 #define AUTH_PRIVATE(auth) (struct ad_private *)auth->ah_private
63 #define ALLOC(object_type) (object_type *) mem_alloc(sizeof (object_type))
64 #define FREE(ptr, size) mem_free((char *)(ptr), (int)size)
65 #define ATTEMPT(xdr_op) if (!(xdr_op))\
68 #define gettimeofday(tvp, tzp) uniqtime(tvp)
70 static void authdes_nextverf(AUTH
*);
71 static bool_t
authdes_marshal(AUTH
*, XDR
*, struct cred
*);
72 static bool_t
authdes_validate(AUTH
*, struct opaque_auth
*);
73 static bool_t
authdes_refresh(AUTH
*, struct rpc_msg
*, cred_t
*);
74 static void authdes_destroy(AUTH
*);
75 static bool_t
synchronize(struct knetconfig
*, struct netbuf
*,
76 int, struct timeval
*);
78 static struct auth_ops
*authdes_ops(void);
81 * This struct is pointed to by the ah_private field of an "AUTH *"
84 char *ad_fullname
; /* client's full name */
85 uint_t ad_fullnamelen
; /* length of name, rounded up */
86 char *ad_servername
; /* server's full name */
87 uint_t ad_servernamelen
; /* length of name, rounded up */
88 uint_t ad_window
; /* client specified window */
89 bool_t ad_dosync
; /* synchronize? */
90 struct netbuf ad_syncaddr
; /* remote host to synch with */
91 struct knetconfig ad_synconfig
; /* netconfig for the synch host */
92 int ad_calltype
; /* use rpc or straight call for sync */
93 struct timeval ad_timediff
; /* server's time - client's time */
94 uint32_t ad_nickname
; /* server's nickname for client */
95 struct authdes_cred ad_cred
; /* storage for credential */
96 struct authdes_verf ad_verf
; /* storage for verifier */
97 struct timeval ad_timestamp
; /* timestamp sent */
98 des_block ad_xkey
; /* encrypted conversation key */
103 * Create the client des authentication object
107 authdes_create(char *servername
, uint_t window
, struct netbuf
*syncaddr
,
108 struct knetconfig
*synconfig
, des_block
*ckey
, int calltype
,
112 struct ad_private
*ad
;
113 char namebuf
[MAXNETNAMELEN
+1];
123 * Allocate everything now
126 ad
= ALLOC(struct ad_private
);
127 bzero(ad
, sizeof (struct ad_private
));
128 if ((stat
= kgetnetname(namebuf
)) != 0) {
130 "authdes_create: unable to get client's netname: %s (error %d)",
131 clnt_sperrno(stat
), stat
);
135 ad
->ad_fullnamelen
= (uint_t
)RNDUP(strlen(namebuf
));
136 ad
->ad_fullname
= mem_alloc(ad
->ad_fullnamelen
+ 1);
138 ad
->ad_servernamelen
= (uint_t
)strlen(servername
);
139 ad
->ad_servername
= mem_alloc(ad
->ad_servernamelen
+ 1);
141 if (auth
== NULL
|| ad
== NULL
|| ad
->ad_fullname
== NULL
||
142 ad
->ad_servername
== NULL
) {
143 cmn_err(CE_NOTE
, "authdes_create: out of memory");
149 * Set up private data
151 bcopy(namebuf
, ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
152 bcopy(servername
, ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
153 if (syncaddr
!= NULL
) {
154 ad
->ad_syncaddr
= *syncaddr
;
155 ad
->ad_synconfig
= *synconfig
;
156 ad
->ad_dosync
= TRUE
;
157 ad
->ad_calltype
= calltype
;
159 ad
->ad_timediff
.tv_sec
= 0;
160 ad
->ad_timediff
.tv_usec
= 0;
161 ad
->ad_dosync
= FALSE
;
163 ad
->ad_window
= window
;
165 if ((stat
= key_gendes(&auth
->ah_key
)) != RPC_SUCCESS
) {
167 "authdes_create: unable to gen conversation key: %s (error %d)",
168 clnt_sperrno(stat
), stat
);
169 if (stat
== RPC_INTR
)
171 else if (stat
== RPC_TIMEDOUT
)
174 error
= EINVAL
; /* XXX */
178 auth
->ah_key
= *ckey
;
183 auth
->ah_cred
.oa_flavor
= AUTH_DES
;
184 auth
->ah_verf
.oa_flavor
= AUTH_DES
;
185 auth
->ah_ops
= authdes_ops();
186 auth
->ah_private
= (caddr_t
)ad
;
188 if (!authdes_refresh(auth
, NULL
, CRED()))
195 if (ad
!= NULL
&& ad
->ad_fullname
!= NULL
)
196 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
197 if (ad
!= NULL
&& ad
->ad_servername
!= NULL
)
198 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
200 FREE(ad
, sizeof (struct ad_private
));
202 FREE(auth
, sizeof (AUTH
));
203 return ((error
== 0) ? EINVAL
: error
); /* XXX */
207 * Implement the five authentication operations
215 authdes_nextverf(AUTH
*auth
)
217 /* what the heck am I supposed to do??? */
225 authdes_marshal(AUTH
*auth
, XDR
*xdrs
, struct cred
*cr
)
227 /* LINTED pointer alignment */
228 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
229 struct authdes_cred
*cred
= &ad
->ad_cred
;
230 struct authdes_verf
*verf
= &ad
->ad_verf
;
231 des_block cryptbuf
[2];
238 * Figure out the "time", accounting for any time difference
239 * with the server if necessary.
241 (void) gettimeofday(&ad
->ad_timestamp
, NULL
);
242 ad
->ad_timestamp
.tv_sec
+= ad
->ad_timediff
.tv_sec
;
243 ad
->ad_timestamp
.tv_usec
+= ad
->ad_timediff
.tv_usec
;
244 if (ad
->ad_timestamp
.tv_usec
>= MILLION
) {
245 ad
->ad_timestamp
.tv_usec
-= MILLION
;
246 ad
->ad_timestamp
.tv_sec
+= 1;
250 * XDR the timestamp and possibly some other things, then
253 ixdr
= (int32_t *)cryptbuf
;
254 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_sec
);
255 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_usec
);
256 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
257 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
);
258 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
- 1);
259 ivec
.key
.high
= ivec
.key
.low
= 0;
260 status
= cbc_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
261 2 * sizeof (des_block
), DES_ENCRYPT
, (char *)&ivec
);
263 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
264 sizeof (des_block
), DES_ENCRYPT
);
266 if (DES_FAILED(status
)) {
267 cmn_err(CE_NOTE
, "authdes_marshal: DES encryption failure");
270 ad
->ad_verf
.adv_xtimestamp
= cryptbuf
[0];
271 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
272 ad
->ad_cred
.adc_fullname
.window
= cryptbuf
[1].key
.high
;
273 ad
->ad_verf
.adv_winverf
= cryptbuf
[1].key
.low
;
275 ad
->ad_cred
.adc_nickname
= ad
->ad_nickname
;
276 ad
->ad_verf
.adv_winverf
= 0;
280 * Serialize the credential and verifier into opaque
281 * authentication data.
283 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
284 len
= ((1 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT
+
287 len
= (1 + 1) * BYTES_PER_XDR_UNIT
;
289 if (ixdr
= xdr_inline(xdrs
, 2 * BYTES_PER_XDR_UNIT
)) {
290 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
291 IXDR_PUT_INT32(ixdr
, len
);
293 ATTEMPT(xdr_putint32(xdrs
,
294 (int32_t *)&auth
->ah_cred
.oa_flavor
));
295 ATTEMPT(xdr_putint32(xdrs
, (int32_t *)&len
));
297 ATTEMPT(xdr_authdes_cred(xdrs
, cred
));
299 len
= (2 + 1) * BYTES_PER_XDR_UNIT
;
300 if (ixdr
= xdr_inline(xdrs
, 2 * BYTES_PER_XDR_UNIT
)) {
301 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
302 IXDR_PUT_INT32(ixdr
, len
);
304 ATTEMPT(xdr_putint32(xdrs
,
305 (int32_t *)&auth
->ah_verf
.oa_flavor
));
306 ATTEMPT(xdr_putint32(xdrs
, (int32_t *)&len
));
308 ATTEMPT(xdr_authdes_verf(xdrs
, verf
));
316 authdes_validate(AUTH
*auth
, struct opaque_auth
*rverf
)
318 /* LINTED pointer alignment */
319 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
320 struct authdes_verf verf
;
325 if (rverf
->oa_length
!= (2 + 1) * BYTES_PER_XDR_UNIT
)
328 /* LINTED pointer alignment */
329 ixdr
= (uint32_t *)rverf
->oa_base
;
330 buf
.key
.high
= (uint32_t)*ixdr
++;
331 buf
.key
.low
= (uint32_t)*ixdr
++;
332 verf
.adv_int_u
= IXDR_GET_U_INT32(ixdr
);
335 * Decrypt the timestamp
337 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)&buf
,
338 sizeof (des_block
), DES_DECRYPT
);
340 if (DES_FAILED(status
)) {
341 cmn_err(CE_NOTE
, "authdes_validate: DES decryption failure");
346 * xdr the decrypted timestamp
348 /* LINTED pointer alignment */
349 ixdr
= (uint32_t *)buf
.c
;
350 verf
.adv_timestamp
.tv_sec
= IXDR_GET_INT32(ixdr
) + 1;
351 verf
.adv_timestamp
.tv_usec
= IXDR_GET_INT32(ixdr
);
356 if (bcmp((char *)&ad
->ad_timestamp
, (char *)&verf
.adv_timestamp
,
357 sizeof (struct timeval
)) != 0) {
358 cmn_err(CE_NOTE
, "authdes_validate: verifier mismatch");
363 * We have a nickname now, let's use it
365 ad
->ad_nickname
= verf
.adv_nickname
;
366 ad
->ad_cred
.adc_namekind
= ADN_NICKNAME
;
373 * msg is a dummy argument here.
377 authdes_refresh(AUTH
*auth
, struct rpc_msg
*msg
, cred_t
*cr
)
379 /* LINTED pointer alignment */
380 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
381 struct authdes_cred
*cred
= &ad
->ad_cred
;
385 !synchronize(&ad
->ad_synconfig
, &ad
->ad_syncaddr
,
386 ad
->ad_calltype
, &ad
->ad_timediff
)) {
388 * Hope the clocks are synced!
390 timerclear(&ad
->ad_timediff
);
392 "authdes_refresh: unable to synchronize with server %s", ad
->ad_servername
);
394 ad
->ad_xkey
= auth
->ah_key
;
395 if ((stat
= key_encryptsession(ad
->ad_servername
, &ad
->ad_xkey
, cr
)) !=
398 "authdes_refresh: unable to encrypt conversation key for user (uid %d): "
400 (int)crgetuid(cr
), clnt_sperrno(stat
), stat
);
403 cred
->adc_fullname
.key
= ad
->ad_xkey
;
404 cred
->adc_namekind
= ADN_FULLNAME
;
405 cred
->adc_fullname
.name
= ad
->ad_fullname
;
413 authdes_destroy(AUTH
*auth
)
415 /* LINTED pointer alignment */
416 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
418 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
419 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
420 FREE(ad
, sizeof (struct ad_private
));
421 FREE(auth
, sizeof (AUTH
));
426 * Synchronize with the server at the given address, that is,
427 * adjust timep to reflect the delta between our clocks
430 synchronize(struct knetconfig
*synconfig
, struct netbuf
*syncaddr
, int calltype
,
431 struct timeval
*timep
)
433 struct timeval mytime
;
434 struct timeval timout
;
436 timout
.tv_sec
= RTIME_TIMEOUT
;
438 if (rtime(synconfig
, syncaddr
, calltype
, timep
, &timout
) < 0)
440 (void) gettimeofday(&mytime
, NULL
);
441 timep
->tv_sec
-= mytime
.tv_sec
;
442 if (mytime
.tv_usec
> timep
->tv_usec
) {
444 timep
->tv_usec
+= MILLION
;
446 timep
->tv_usec
-= mytime
.tv_usec
;
450 static struct auth_ops
*
453 static struct auth_ops ops
;
455 mutex_enter(&authdes_ops_lock
);
456 if (ops
.ah_nextverf
== NULL
) {
457 ops
.ah_nextverf
= authdes_nextverf
;
458 ops
.ah_marshal
= authdes_marshal
;
459 ops
.ah_validate
= authdes_validate
;
460 ops
.ah_refresh
= authdes_refresh
;
461 ops
.ah_destroy
= authdes_destroy
;
462 ops
.ah_wrap
= authany_wrap
;
463 ops
.ah_unwrap
= authany_unwrap
;
465 mutex_exit(&authdes_ops_lock
);