2 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of Sun Microsystems, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 1988 by Sun Microsystems, Inc.
32 * auth_des.c, client-side implementation of DES authentication
36 //#include <pthread.h>
37 #include <reentrant.h>
43 //#include <sys/cdefs.h>
44 #include <rpc/des_crypt.h>
46 #include <rpc/types.h>
48 #include <rpc/auth_des.h>
51 //#include <sys/socket.h>
53 #include <rpcsvc/nis.h>
55 #if defined(LIBC_SCCS) && !defined(lint)
57 //#include <sys/cdefs.h>
59 #define USEC_PER_SEC 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)) return (FALSE)
67 extern bool_t
xdr_authdes_cred( XDR
*, struct authdes_cred
*);
68 extern bool_t
xdr_authdes_verf( XDR
*, struct authdes_verf
*);
69 extern int key_encryptsession_pk();
71 extern bool_t
__rpc_get_time_offset(struct timeval
*, nis_server
*, char *,
75 * DES authenticator operations vector
77 static void authdes_nextverf(AUTH
*);
78 static bool_t
authdes_marshal(AUTH
*, XDR
*);
79 static bool_t
authdes_validate(AUTH
*, struct opaque_auth
*);
80 static bool_t
authdes_refresh(AUTH
*, void *);
81 static void authdes_destroy(AUTH
*);
83 static struct auth_ops
*authdes_ops(void);
86 * This struct is pointed to by the ah_private field of an "AUTH *"
89 char *ad_fullname
; /* client's full name */
90 u_int ad_fullnamelen
; /* length of name, rounded up */
91 char *ad_servername
; /* server's full name */
92 u_int ad_servernamelen
; /* length of name, rounded up */
93 u_int ad_window
; /* client specified window */
94 bool_t ad_dosync
; /* synchronize? */
95 struct netbuf ad_syncaddr
; /* remote host to synch with */
96 char *ad_timehost
; /* remote host to synch with */
97 struct timeval ad_timediff
; /* server's time - client's time */
98 u_int ad_nickname
; /* server's nickname for client */
99 struct authdes_cred ad_cred
; /* storage for credential */
100 struct authdes_verf ad_verf
; /* storage for verifier */
101 struct timeval ad_timestamp
; /* timestamp sent */
102 des_block ad_xkey
; /* encrypted conversation key */
103 u_char ad_pkey
[1024]; /* Server's actual public key */
104 char *ad_netid
; /* Timehost netid */
105 char *ad_uaddr
; /* Timehost uaddr */
106 nis_server
*ad_nis_srvr
; /* NIS+ server struct */
109 AUTH
*authdes_pk_seccreate(const char *, netobj
*, u_int
, const char *,
110 const des_block
*, nis_server
*);
113 * documented version of authdes_seccreate
116 servername: network name of server
118 timehost: optional hostname to sync with
119 ckey: optional conversation key to use
123 authdes_seccreate(const char *servername
, const u_int win
,
124 const char *timehost
, const des_block
*ckey
)
126 u_char pkey_data
[1024];
130 if (! getpublickey(servername
, (char *) pkey_data
)) {
132 // "authdes_seccreate: no public key found for %s",
137 pkey
.n_bytes
= (char *) pkey_data
;
138 pkey
.n_len
= (u_int
)strlen((char *)pkey_data
) + 1;
139 dummy
= authdes_pk_seccreate(servername
, &pkey
, win
, timehost
,
145 * Slightly modified version of authdessec_create which takes the public key
146 * of the server principal as an argument. This spares us a call to
147 * getpublickey() which in the nameserver context can cause a deadlock.
150 authdes_pk_seccreate(const char *servername
, netobj
*pkey
, u_int window
,
151 const char *timehost
, const des_block
*ckey
, nis_server
*srvr
)
154 struct ad_private
*ad
;
155 char namebuf
[MAXNETNAMELEN
+1];
158 * Allocate everything now
162 //syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
165 ad
= ALLOC(struct ad_private
);
167 //syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
170 ad
->ad_fullname
= ad
->ad_servername
= NULL
; /* Sanity reasons */
171 ad
->ad_timehost
= NULL
;
174 ad
->ad_nis_srvr
= NULL
;
175 ad
->ad_timediff
.tv_sec
= 0;
176 ad
->ad_timediff
.tv_usec
= 0;
177 memcpy(ad
->ad_pkey
, pkey
->n_bytes
, pkey
->n_len
);
178 if (!getnetname(namebuf
))
180 ad
->ad_fullnamelen
= RNDUP((u_int
) strlen(namebuf
));
181 ad
->ad_fullname
= (char *)mem_alloc(ad
->ad_fullnamelen
+ 1);
182 ad
->ad_servernamelen
= strlen(servername
);
183 ad
->ad_servername
= (char *)mem_alloc(ad
->ad_servernamelen
+ 1);
185 if (ad
->ad_fullname
== NULL
|| ad
->ad_servername
== NULL
) {
186 //syslog(LOG_ERR, "authdes_seccreate: out of memory");
189 if (timehost
!= NULL
) {
190 ad
->ad_timehost
= (char *)mem_alloc(strlen(timehost
) + 1);
191 if (ad
->ad_timehost
== NULL
) {
192 //syslog(LOG_ERR, "authdes_seccreate: out of memory");
195 memcpy(ad
->ad_timehost
, timehost
, strlen(timehost
) + 1);
196 ad
->ad_dosync
= TRUE
;
197 } else if (srvr
!= NULL
) {
198 ad
->ad_nis_srvr
= srvr
; /* transient */
199 ad
->ad_dosync
= TRUE
;
201 ad
->ad_dosync
= FALSE
;
203 memcpy(ad
->ad_fullname
, namebuf
, ad
->ad_fullnamelen
+ 1);
204 memcpy(ad
->ad_servername
, servername
, ad
->ad_servernamelen
+ 1);
205 ad
->ad_window
= window
;
207 if (key_gendes(&auth
->ah_key
) < 0) {
209 // "authdes_seccreate: keyserv(1m) is unable to generate session key");
213 auth
->ah_key
= *ckey
;
219 auth
->ah_cred
.oa_flavor
= AUTH_DES
;
220 auth
->ah_verf
.oa_flavor
= AUTH_DES
;
221 auth
->ah_ops
= authdes_ops();
222 auth
->ah_private
= (caddr_t
)ad
;
224 if (!authdes_refresh(auth
, NULL
)) {
227 ad
->ad_nis_srvr
= NULL
; /* not needed any longer */
232 FREE(auth
, sizeof (AUTH
));
235 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
236 if (ad
->ad_servername
)
237 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
239 FREE(ad
->ad_timehost
, strlen(ad
->ad_timehost
) + 1);
241 FREE(ad
->ad_netid
, strlen(ad
->ad_netid
) + 1);
243 FREE(ad
->ad_uaddr
, strlen(ad
->ad_uaddr
) + 1);
244 FREE(ad
, sizeof (struct ad_private
));
250 * Implement the five authentication operations
259 authdes_nextverf(AUTH
*auth
)
261 /* what the heck am I supposed to do??? */
269 authdes_marshal(AUTH
*auth
, XDR
*xdrs
)
271 /* LINTED pointer alignment */
272 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
273 struct authdes_cred
*cred
= &ad
->ad_cred
;
274 struct authdes_verf
*verf
= &ad
->ad_verf
;
275 des_block cryptbuf
[2];
282 * Figure out the "time", accounting for any time difference
283 * with the server if necessary.
285 (void) gettimeofday(&ad
->ad_timestamp
, (struct timezone
*)NULL
);
286 ad
->ad_timestamp
.tv_sec
+= ad
->ad_timediff
.tv_sec
;
287 ad
->ad_timestamp
.tv_usec
+= ad
->ad_timediff
.tv_usec
;
288 while (ad
->ad_timestamp
.tv_usec
>= USEC_PER_SEC
) {
289 ad
->ad_timestamp
.tv_usec
-= USEC_PER_SEC
;
290 ad
->ad_timestamp
.tv_sec
++;
294 * XDR the timestamp and possibly some other things, then
297 ixdr
= (rpc_inline_t
*)cryptbuf
;
298 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_sec
);
299 IXDR_PUT_INT32(ixdr
, ad
->ad_timestamp
.tv_usec
);
300 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
301 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
);
302 IXDR_PUT_U_INT32(ixdr
, ad
->ad_window
- 1);
303 ivec
.key
.high
= ivec
.key
.low
= 0;
304 status
= cbc_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
305 (u_int
) 2 * sizeof (des_block
),
306 DES_ENCRYPT
| DES_HW
, (char *)&ivec
);
308 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)cryptbuf
,
309 (u_int
) sizeof (des_block
),
310 DES_ENCRYPT
| DES_HW
);
312 if (DES_FAILED(status
)) {
313 //syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
316 ad
->ad_verf
.adv_xtimestamp
= cryptbuf
[0];
317 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
318 ad
->ad_cred
.adc_fullname
.window
= cryptbuf
[1].key
.high
;
319 ad
->ad_verf
.adv_winverf
= cryptbuf
[1].key
.low
;
321 ad
->ad_cred
.adc_nickname
= ad
->ad_nickname
;
322 ad
->ad_verf
.adv_winverf
= 0;
326 * Serialize the credential and verifier into opaque
327 * authentication data.
329 if (ad
->ad_cred
.adc_namekind
== ADN_FULLNAME
) {
330 len
= ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT
+ ad
->ad_fullnamelen
);
332 len
= (1 + 1)*BYTES_PER_XDR_UNIT
;
335 if ((ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
))) {
336 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
337 IXDR_PUT_INT32(ixdr
, len
);
339 ATTEMPT(xdr_putint32(xdrs
, (int *)&auth
->ah_cred
.oa_flavor
));
340 ATTEMPT(xdr_putint32(xdrs
, &len
));
342 ATTEMPT(xdr_authdes_cred(xdrs
, cred
));
344 len
= (2 + 1)*BYTES_PER_XDR_UNIT
;
345 if ((ixdr
= xdr_inline(xdrs
, 2*BYTES_PER_XDR_UNIT
))) {
346 IXDR_PUT_INT32(ixdr
, AUTH_DES
);
347 IXDR_PUT_INT32(ixdr
, len
);
349 ATTEMPT(xdr_putint32(xdrs
, (int *)&auth
->ah_verf
.oa_flavor
));
350 ATTEMPT(xdr_putint32(xdrs
, &len
));
352 ATTEMPT(xdr_authdes_verf(xdrs
, verf
));
361 authdes_validate(AUTH
*auth
, struct opaque_auth
*rverf
)
363 /* LINTED pointer alignment */
364 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
365 struct authdes_verf verf
;
370 if (rverf
->oa_length
!= (2 + 1) * BYTES_PER_XDR_UNIT
) {
373 /* LINTED pointer alignment */
374 ixdr
= (uint32_t *)rverf
->oa_base
;
375 buf
.key
.high
= (uint32_t)*ixdr
++;
376 buf
.key
.low
= (uint32_t)*ixdr
++;
377 verf
.adv_int_u
= (uint32_t)*ixdr
++;
380 * Decrypt the timestamp
382 status
= ecb_crypt((char *)&auth
->ah_key
, (char *)&buf
,
383 (u_int
)sizeof (des_block
), DES_DECRYPT
| DES_HW
);
385 if (DES_FAILED(status
)) {
386 //syslog(LOG_ERR, "authdes_validate: DES decryption failure");
391 * xdr the decrypted timestamp
393 /* LINTED pointer alignment */
394 ixdr
= (uint32_t *)buf
.c
;
395 verf
.adv_timestamp
.tv_sec
= IXDR_GET_INT32(ixdr
) + 1;
396 verf
.adv_timestamp
.tv_usec
= IXDR_GET_INT32(ixdr
);
401 if (bcmp((char *)&ad
->ad_timestamp
, (char *)&verf
.adv_timestamp
,
402 sizeof(struct timeval
)) != 0) {
403 //syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
408 * We have a nickname now, let's use it
410 ad
->ad_nickname
= verf
.adv_nickname
;
411 ad
->ad_cred
.adc_namekind
= ADN_NICKNAME
;
420 authdes_refresh(AUTH
*auth
, void *dummy
)
422 /* LINTED pointer alignment */
423 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
424 struct authdes_cred
*cred
= &ad
->ad_cred
;
432 ok
= __rpc_get_time_offset(&ad
->ad_timediff
, ad
->ad_nis_srvr
,
433 ad
->ad_timehost
, &(ad
->ad_uaddr
),
438 * Hope the clocks are synced!
442 // "authdes_refresh: unable to synchronize clock");
445 ad
->ad_xkey
= auth
->ah_key
;
446 pkey
.n_bytes
= (char *)(ad
->ad_pkey
);
447 pkey
.n_len
= (u_int
)strlen((char *)ad
->ad_pkey
) + 1;
448 if (key_encryptsession_pk(ad
->ad_servername
, &pkey
, &ad
->ad_xkey
) < 0) {
450 // "authdes_refresh: keyserv(1m) is unable to encrypt session key");
453 cred
->adc_fullname
.key
= ad
->ad_xkey
;
454 cred
->adc_namekind
= ADN_FULLNAME
;
455 cred
->adc_fullname
.name
= ad
->ad_fullname
;
464 authdes_destroy(AUTH
*auth
)
466 /* LINTED pointer alignment */
467 struct ad_private
*ad
= AUTH_PRIVATE(auth
);
469 FREE(ad
->ad_fullname
, ad
->ad_fullnamelen
+ 1);
470 FREE(ad
->ad_servername
, ad
->ad_servernamelen
+ 1);
472 FREE(ad
->ad_timehost
, strlen(ad
->ad_timehost
) + 1);
474 FREE(ad
->ad_netid
, strlen(ad
->ad_netid
) + 1);
476 FREE(ad
->ad_uaddr
, strlen(ad
->ad_uaddr
) + 1);
477 FREE(ad
, sizeof (struct ad_private
));
478 FREE(auth
, sizeof(AUTH
));
481 static struct auth_ops
*
484 static struct auth_ops ops
;
485 extern mutex_t authdes_ops_lock
;
487 /* VARIABLES PROTECTED BY ops_lock: ops */
489 mutex_lock(&authdes_ops_lock
);
490 if (ops
.ah_nextverf
== NULL
) {
491 ops
.ah_nextverf
= authdes_nextverf
;
492 ops
.ah_marshal
= authdes_marshal
;
493 ops
.ah_validate
= authdes_validate
;
494 ops
.ah_refresh
= authdes_refresh
;
495 ops
.ah_destroy
= authdes_destroy
;
497 mutex_unlock(&authdes_ops_lock
);