2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
29 * @(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI
30 * $FreeBSD: src/lib/libc/rpc/auth_des.c,v 1.10 2006/02/27 22:10:58 deischen Exp $
31 * $DragonFly: src/lib/libc/rpc/auth_des.c,v 1.5 2005/11/13 12:27:04 swildner Exp $
34 * Copyright (c) 1988 by Sun Microsystems, Inc.
37 * auth_des.c, client-side implementation of DES authentication
40 #include "namespace.h"
41 #include "reentrant.h"
47 #include <sys/cdefs.h>
48 #include <rpc/des_crypt.h>
50 #include <rpc/types.h>
52 #include <rpc/auth_des.h>
55 #include <sys/socket.h>
57 #include <rpcsvc/nis.h>
58 #include "un-namespace.h"
61 #define USEC_PER_SEC 1000000
62 #define RTIME_TIMEOUT 5 /* seconds to wait for sync */
64 #define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private
65 #define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type))
66 #define FREE(ptr, size) mem_free((char *)(ptr), (int) size)
67 #define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
69 extern bool_t
xdr_authdes_cred(XDR
*, struct authdes_cred
*);
70 extern bool_t
xdr_authdes_verf(XDR
*, struct authdes_verf
*);
72 extern bool_t
__rpc_get_time_offset(struct timeval
*, nis_server
*, char *,
77 * DES authenticator operations vector
79 static void authdes_nextverf(AUTH
*);
80 static bool_t
authdes_marshal(AUTH
*, XDR
*);
81 static bool_t
authdes_validate(AUTH
*, struct opaque_auth
*);
82 static bool_t
authdes_refresh(AUTH
*, void *);
83 static void authdes_destroy(AUTH
*);
85 static struct auth_ops
*authdes_ops(void);
88 * This struct is pointed to by the ah_private field of an "AUTH *"
91 char *ad_fullname
; /* client's full name */
92 u_int ad_fullnamelen
; /* length of name, rounded up */
93 char *ad_servername
; /* server's full name */
94 u_int ad_servernamelen
; /* length of name, rounded up */
95 u_int ad_window
; /* client specified window */
96 bool_t ad_dosync
; /* synchronize? */
97 struct netbuf ad_syncaddr
; /* remote host to synch with */
98 char *ad_timehost
; /* remote host to synch with */
99 struct timeval ad_timediff
; /* server's time - client's time */
100 u_int ad_nickname
; /* server's nickname for client */
101 struct authdes_cred ad_cred
; /* storage for credential */
102 struct authdes_verf ad_verf
; /* storage for verifier */
103 struct timeval ad_timestamp
; /* timestamp sent */
104 des_block ad_xkey
; /* encrypted conversation key */
105 u_char ad_pkey
[1024]; /* Server's actual public key */
106 char *ad_netid
; /* Timehost netid */
107 char *ad_uaddr
; /* Timehost uaddr */
108 nis_server
*ad_nis_srvr
; /* NIS+ server struct */
111 AUTH
*authdes_pk_seccreate(const char *, netobj
*, u_int
, const char *,
112 const des_block
*, nis_server
*);
114 * documented version of authdes_seccreate
117 servername: network name of server
119 timehost: optional hostname to sync with
120 ckey: optional conversation key to use
124 authdes_seccreate(const char *servername
, const u_int win
,
125 const char *timehost
, const des_block
*ckey
)
127 u_char pkey_data
[1024];
131 if (! getpublickey(servername
, (char *) pkey_data
)) {
133 "authdes_seccreate: no public key found for %s",
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
,
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.
151 authdes_pk_seccreate(const char *servername
, netobj
*pkey
, u_int window
,
152 const char *timehost
, const des_block
*ckey
,
156 struct ad_private
*ad
;
157 char namebuf
[MAXNETNAMELEN
+1];
160 * Allocate everything now
164 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
167 ad
= ALLOC(struct ad_private
);
169 syslog(LOG_ERR
, "authdes_pk_seccreate: out of memory");
172 ad
->ad_fullname
= ad
->ad_servername
= NULL
; /* Sanity reasons */
173 ad
->ad_timehost
= NULL
;
176 ad
->ad_nis_srvr
= NULL
;
177 ad
->ad_timediff
.tv_sec
= 0;
178 ad
->ad_timediff
.tv_usec
= 0;
179 memcpy(ad
->ad_pkey
, pkey
->n_bytes
, pkey
->n_len
);
180 if (!getnetname(namebuf
))
182 ad
->ad_fullnamelen
= RNDUP((u_int
) strlen(namebuf
));
183 ad
->ad_fullname
= (char *)mem_alloc(ad
->ad_fullnamelen
+ 1);
184 ad
->ad_servernamelen
= strlen(servername
);
185 ad
->ad_servername
= (char *)mem_alloc(ad
->ad_servernamelen
+ 1);
187 if (ad
->ad_fullname
== NULL
|| ad
->ad_servername
== NULL
) {
188 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
191 if (timehost
!= NULL
) {
192 ad
->ad_timehost
= (char *)mem_alloc(strlen(timehost
) + 1);
193 if (ad
->ad_timehost
== NULL
) {
194 syslog(LOG_ERR
, "authdes_seccreate: out of memory");
197 memcpy(ad
->ad_timehost
, timehost
, strlen(timehost
) + 1);
198 ad
->ad_dosync
= TRUE
;
199 } else if (srvr
!= NULL
) {
200 ad
->ad_nis_srvr
= srvr
; /* transient */
201 ad
->ad_dosync
= TRUE
;
203 ad
->ad_dosync
= FALSE
;
205 memcpy(ad
->ad_fullname
, namebuf
, ad
->ad_fullnamelen
+ 1);
206 memcpy(ad
->ad_servername
, servername
, ad
->ad_servernamelen
+ 1);
207 ad
->ad_window
= window
;
209 if (key_gendes(&auth
->ah_key
) < 0) {
211 "authdes_seccreate: keyserv(1m) is unable to generate session key");
215 auth
->ah_key
= *ckey
;
221 auth
->ah_cred
.oa_flavor
= AUTH_DES
;
222 auth
->ah_verf
.oa_flavor
= AUTH_DES
;
223 auth
->ah_ops
= authdes_ops();
224 auth
->ah_private
= (caddr_t
)ad
;
226 if (!authdes_refresh(auth
, NULL
)) {
229 ad
->ad_nis_srvr
= NULL
; /* not needed any longer */
234 FREE(auth
, sizeof (AUTH
));
237 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
238 if (ad
->ad_servername
)
239 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
241 FREE(ad
->ad_timehost
, strlen(ad
->ad_timehost
) + 1);
243 FREE(ad
->ad_netid
, strlen(ad
->ad_netid
) + 1);
245 FREE(ad
->ad_uaddr
, strlen(ad
->ad_uaddr
) + 1);
246 FREE(ad
, sizeof (struct ad_private
));
252 * Implement the five authentication operations
261 authdes_nextverf(AUTH
*auth
)
263 /* what the heck am I supposed to do??? */
271 authdes_marshal(AUTH
*auth
, XDR
*xdrs
)
273 /* LINTED pointer alignment */
274 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
275 struct authdes_cred
*cred
= &ad
->ad_cred
;
276 struct authdes_verf
*verf
= &ad
->ad_verf
;
277 des_block cryptbuf
[2];
284 * Figure out the "time", accounting for any time difference
285 * with the server if necessary.
287 gettimeofday(&ad
->ad_timestamp
, NULL
);
288 ad
->ad_timestamp
.tv_sec
+= ad
->ad_timediff
.tv_sec
;
289 ad
->ad_timestamp
.tv_usec
+= ad
->ad_timediff
.tv_usec
;
290 while (ad
->ad_timestamp
.tv_usec
>= USEC_PER_SEC
) {
291 ad
->ad_timestamp
.tv_usec
-= USEC_PER_SEC
;
292 ad
->ad_timestamp
.tv_sec
++;
296 * XDR the timestamp and possibly some other things, then
299 ixdr
= (rpc_inline_t
*)cryptbuf
;
300 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_sec
);
301 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_usec
);
302 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
303 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
);
304 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
- 1);
305 ivec
.key
.high
= ivec
.key
.low
= 0;
306 status
= cbc_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
307 (u_int
) 2 * sizeof (des_block
),
308 DES_ENCRYPT
| DES_HW
, (char *)&ivec
);
310 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
311 (u_int
) sizeof (des_block
),
312 DES_ENCRYPT
| DES_HW
);
314 if (DES_FAILED(status
)) {
315 syslog(LOG_ERR
, "authdes_marshal: DES encryption failure");
318 ad
->ad_verf
.adv_xtimestamp
= cryptbuf
[0];
319 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
320 ad
->ad_cred
.adc_fullname
.window
= cryptbuf
[1].key
.high
;
321 ad
->ad_verf
.adv_winverf
= cryptbuf
[1].key
.low
;
323 ad
->ad_cred
.adc_nickname
= ad
->ad_nickname
;
324 ad
->ad_verf
.adv_winverf
= 0;
328 * Serialize the credential and verifier into opaque
329 * authentication data.
331 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
332 len
= ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT
+ ad
->ad_fullnamelen
);
334 len
= (1 + 1)*BYTES_PER_XDR_UNIT
;
337 if ((ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
))) {
338 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
339 IXDR_PUT_INT32(ixdr
, len
);
341 ATTEMPT(xdr_putint32(xdrs
, (int *)&auth
->ah_cred
.oa_flavor
));
342 ATTEMPT(xdr_putint32(xdrs
, &len
));
344 ATTEMPT(xdr_authdes_cred(xdrs
, cred
));
346 len
= (2 + 1)*BYTES_PER_XDR_UNIT
;
347 if ((ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
))) {
348 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
349 IXDR_PUT_INT32(ixdr
, len
);
351 ATTEMPT(xdr_putint32(xdrs
, (int *)&auth
->ah_verf
.oa_flavor
));
352 ATTEMPT(xdr_putint32(xdrs
, &len
));
354 ATTEMPT(xdr_authdes_verf(xdrs
, verf
));
363 authdes_validate(AUTH
*auth
, struct opaque_auth
*rverf
)
365 /* LINTED pointer alignment */
366 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
367 struct authdes_verf verf
;
372 if (rverf
->oa_length
!= (2 + 1) * BYTES_PER_XDR_UNIT
) {
375 /* LINTED pointer alignment */
376 ixdr
= (uint32_t *)rverf
->oa_base
;
377 buf
.key
.high
= (uint32_t)*ixdr
++;
378 buf
.key
.low
= (uint32_t)*ixdr
++;
379 verf
.adv_int_u
= (uint32_t)*ixdr
++;
382 * Decrypt the timestamp
384 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)&buf
,
385 (u_int
)sizeof (des_block
), DES_DECRYPT
| DES_HW
);
387 if (DES_FAILED(status
)) {
388 syslog(LOG_ERR
, "authdes_validate: DES decryption failure");
393 * xdr the decrypted timestamp
395 /* LINTED pointer alignment */
396 ixdr
= (uint32_t *)buf
.c
;
397 verf
.adv_timestamp
.tv_sec
= IXDR_GET_INT32(ixdr
) + 1;
398 verf
.adv_timestamp
.tv_usec
= IXDR_GET_INT32(ixdr
);
403 if (bcmp((char *)&ad
->ad_timestamp
, (char *)&verf
.adv_timestamp
,
404 sizeof(struct timeval
)) != 0) {
405 syslog(LOG_DEBUG
, "authdes_validate: verifier mismatch");
410 * We have a nickname now, let's use it
412 ad
->ad_nickname
= verf
.adv_nickname
;
413 ad
->ad_cred
.adc_namekind
= ADN_NICKNAME
;
422 authdes_refresh(AUTH
*auth
, void *dummy
)
424 /* LINTED pointer alignment */
425 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
426 struct authdes_cred
*cred
= &ad
->ad_cred
;
431 ok
= __rpc_get_time_offset(&ad
->ad_timediff
, ad
->ad_nis_srvr
,
432 ad
->ad_timehost
, &(ad
->ad_uaddr
),
436 * Hope the clocks are synced!
440 "authdes_refresh: unable to synchronize clock");
443 ad
->ad_xkey
= auth
->ah_key
;
444 pkey
.n_bytes
= (char *)(ad
->ad_pkey
);
445 pkey
.n_len
= (u_int
)strlen((char *)ad
->ad_pkey
) + 1;
446 if (key_encryptsession_pk(ad
->ad_servername
, &pkey
, &ad
->ad_xkey
) < 0) {
448 "authdes_refresh: keyserv(1m) is unable to encrypt session key");
451 cred
->adc_fullname
.key
= ad
->ad_xkey
;
452 cred
->adc_namekind
= ADN_FULLNAME
;
453 cred
->adc_fullname
.name
= ad
->ad_fullname
;
462 authdes_destroy(AUTH
*auth
)
464 /* LINTED pointer alignment */
465 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
467 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
468 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
470 FREE(ad
->ad_timehost
, strlen(ad
->ad_timehost
) + 1);
472 FREE(ad
->ad_netid
, strlen(ad
->ad_netid
) + 1);
474 FREE(ad
->ad_uaddr
, strlen(ad
->ad_uaddr
) + 1);
475 FREE(ad
, sizeof(struct ad_private
));
476 FREE(auth
, sizeof(AUTH
));
479 static struct auth_ops
*
482 static struct auth_ops ops
;
484 /* VARIABLES PROTECTED BY ops_lock: ops */
486 mutex_lock(&authdes_ops_lock
);
487 if (ops
.ah_nextverf
== NULL
) {
488 ops
.ah_nextverf
= authdes_nextverf
;
489 ops
.ah_marshal
= authdes_marshal
;
490 ops
.ah_validate
= authdes_validate
;
491 ops
.ah_refresh
= authdes_refresh
;
492 ops
.ah_destroy
= authdes_destroy
;
494 mutex_unlock(&authdes_ops_lock
);