6198 Let's EOL cachefs
[illumos-gate.git] / usr / src / lib / libnsl / rpc / auth_des.c
blob4bb4b929c8a5f2d7134c6396374c9d0ef8a999a1
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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
32 * California.
35 #pragma ident "%Z%%M% %I% %E% SMI"
38 * auth_des.c, client-side implementation of DES authentication
42 #include "mt.h"
43 #include "rpc_mt.h"
44 #include <rpc/rpc.h>
45 #include <rpc/des_crypt.h>
46 #include <syslog.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <synch.h>
50 #undef NIS
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 *,
61 char **, 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 *"
68 struct ad_private {
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
96 * win: time to live
97 * timehost: optional hostname to sync with
98 * ckey: optional conversation key to use
101 AUTH *
102 authdes_seccreate(const char *servername, const uint_t win,
103 const char *timehost, const des_block *ckey)
105 uchar_t pkey_data[1024];
106 netobj pkey;
108 if (!getpublickey(servername, (char *)pkey_data)) {
109 syslog(LOG_ERR,
110 "authdes_seccreate: no public key found for %s",
111 servername);
113 return (NULL);
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,
119 ckey, NULL));
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.
128 AUTH *
129 authdes_pk_seccreate(const char *servername, netobj *pkey, uint_t window,
130 const char *timehost, const des_block *ckey, nis_server *srvr)
132 AUTH *auth;
133 struct ad_private *ad;
134 char namebuf[MAXNETNAMELEN+1];
137 * Allocate everything now
139 auth = malloc(sizeof (AUTH));
140 if (auth == NULL) {
141 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
142 return (NULL);
144 ad = malloc(sizeof (struct ad_private));
145 if (ad == NULL) {
146 syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
147 goto failed;
149 ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */
150 ad->ad_timehost = NULL;
151 ad->ad_netid = NULL;
152 ad->ad_uaddr = 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))
158 goto failed;
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");
166 goto failed;
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");
172 goto failed;
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;
179 } else {
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;
185 if (ckey == NULL) {
186 if (key_gendes(&auth->ah_key) < 0) {
187 syslog(LOG_ERR,
188 "authdes_seccreate: keyserv(1m) is unable to generate session key");
189 goto failed;
191 } else
192 auth->ah_key = *ckey;
195 * Set up auth handle
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)) {
203 goto failed;
205 ad->ad_nis_srvr = NULL; /* not needed any longer */
206 return (auth);
208 failed:
209 if (auth)
210 free(auth);
211 if (ad) {
212 if (ad->ad_fullname)
213 free(ad->ad_fullname);
214 if (ad->ad_servername)
215 free(ad->ad_servername);
216 if (ad->ad_timehost)
217 free(ad->ad_timehost);
218 if (ad->ad_netid)
219 free(ad->ad_netid);
220 if (ad->ad_uaddr)
221 free(ad->ad_uaddr);
222 free(ad);
224 return (NULL);
228 * Implement the five authentication operations
232 * 1. Next Verifier
234 /*ARGSUSED*/
235 static void
236 authdes_nextverf(AUTH *auth)
238 /* what the heck am I supposed to do??? */
243 * 2. Marshal
245 static bool_t
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];
253 des_block ivec;
254 int status;
255 int len;
256 rpc_inline_t *ixdr;
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
272 * encrypt them.
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);
284 } else {
285 status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,
286 sizeof (des_block),
287 DES_ENCRYPT | DES_HW);
289 if (DES_FAILED(status)) {
290 syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
291 return (FALSE);
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;
297 } else {
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);
308 } else {
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);
315 } else {
316 if (!xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor))
317 return (FALSE);
318 if (!xdr_putint32(xdrs, &len))
319 return (FALSE);
321 if (!xdr_authdes_cred(xdrs, cred))
322 return (FALSE);
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);
328 } else {
329 if (!xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor))
330 return (FALSE);
331 if (!xdr_putint32(xdrs, &len))
332 return (FALSE);
334 return (xdr_authdes_verf(xdrs, verf));
339 * 3. Validate
341 static bool_t
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;
347 int status;
348 uint32_t *ixdr;
349 des_block buf;
351 if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT)
352 return (FALSE);
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");
367 return (FALSE);
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);
379 * validate
381 if (memcmp(&ad->ad_timestamp, &verf.adv_timestamp,
382 sizeof (struct timeval)) != 0) {
383 syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
384 return (FALSE);
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;
392 return (TRUE);
396 * 4. Refresh
398 /*ARGSUSED*/
399 static bool_t
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;
405 int ok;
406 netobj pkey;
408 if (ad->ad_dosync) {
409 ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
410 ad->ad_timehost, &(ad->ad_uaddr),
411 &(ad->ad_netid));
412 if (!ok) {
414 * Hope the clocks are synced!
416 ad->ad_dosync = 0;
417 syslog(LOG_DEBUG,
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) {
425 syslog(LOG_INFO,
426 "authdes_refresh: keyserv(1m) is unable to encrypt session key");
427 return (FALSE);
429 cred->adc_fullname.key = ad->ad_xkey;
430 cred->adc_namekind = ADN_FULLNAME;
431 cred->adc_fullname.name = ad->ad_fullname;
432 return (TRUE);
437 * 5. Destroy
439 static void
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);
447 if (ad->ad_timehost)
448 free(ad->ad_timehost);
449 if (ad->ad_netid)
450 free(ad->ad_netid);
451 if (ad->ad_uaddr)
452 free(ad->ad_uaddr);
453 free(ad);
454 free(auth);
457 static struct auth_ops *
458 authdes_ops(void)
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);
474 return (&ops);