source: rtems-libbsd/freebsd/lib/libc/rpc/auth_des.c

6-freebsd-12
Last change on this file was bb80d9d, checked in by Sebastian Huber <sebastian.huber@…>, on 08/09/18 at 12:02:09

Update to FreeBSD head 2017-12-01

Git mirror commit e724f51f811a4b2bd29447f8b85ab5c2f9b88266.

Update #3472.

  • Property mode set to 100644
File size: 14.0 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*-
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Copyright (c) 2009, Sun Microsystems, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 * - Redistributions of source code must retain the above copyright notice,
12 *   this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright notice,
14 *   this list of conditions and the following disclaimer in the documentation
15 *   and/or other materials provided with the distribution.
16 * - Neither the name of Sun Microsystems, Inc. nor the names of its
17 *   contributors may be used to endorse or promote products derived
18 *   from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32/*
33 * Copyright (c) 1988 by Sun Microsystems, Inc.
34 */
35/*
36 * auth_des.c, client-side implementation of DES authentication
37 */
38
39#include "namespace.h"
40#include "reentrant.h"
41#include <err.h>
42#include <errno.h>
43#include <string.h>
44#include <stdlib.h>
45#include <unistd.h>
46#include <sys/cdefs.h>
47#include <rpc/des_crypt.h>
48#include <syslog.h>
49#include <rpc/types.h>
50#include <rpc/auth.h>
51#include <rpc/auth_des.h>
52#include <rpc/clnt.h>
53#include <rpc/xdr.h>
54#include <sys/socket.h>
55#undef NIS
56#include <rpcsvc/nis.h>
57#include "un-namespace.h"
58#include "mt_misc.h"
59
60#if defined(LIBC_SCCS) && !defined(lint)
61static char sccsid[] =  "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI";
62#endif
63#include <sys/cdefs.h>
64__FBSDID("$FreeBSD$");
65
66#define USEC_PER_SEC            1000000
67#define RTIME_TIMEOUT           5       /* seconds to wait for sync */
68
69#define AUTH_PRIVATE(auth)      (struct ad_private *) auth->ah_private
70#define ALLOC(object_type)      (object_type *) mem_alloc(sizeof(object_type))
71#define FREE(ptr, size)         mem_free((char *)(ptr), (int) size)
72#define ATTEMPT(xdr_op)         if (!(xdr_op)) return (FALSE)
73
74extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *);
75extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *);
76extern int key_encryptsession_pk(char *, netobj *, des_block *);
77
78extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *,
79        char **, char **);
80
81/*
82 * DES authenticator operations vector
83 */
84static void     authdes_nextverf(AUTH *);
85static bool_t   authdes_marshal(AUTH *, XDR *);
86static bool_t   authdes_validate(AUTH *, struct opaque_auth *);
87static bool_t   authdes_refresh(AUTH *, void *);
88static void     authdes_destroy(AUTH *);
89
90static struct auth_ops *authdes_ops(void);
91
92/*
93 * This struct is pointed to by the ah_private field of an "AUTH *"
94 */
95struct ad_private {
96        char *ad_fullname;              /* client's full name */
97        u_int ad_fullnamelen;           /* length of name, rounded up */
98        char *ad_servername;            /* server's full name */
99        u_int ad_servernamelen;         /* length of name, rounded up */
100        u_int ad_window;                /* client specified window */
101        bool_t ad_dosync;               /* synchronize? */             
102        struct netbuf ad_syncaddr;      /* remote host to synch with */
103        char *ad_timehost;              /* remote host to synch with */
104        struct timeval ad_timediff;     /* server's time - client's time */
105        u_int ad_nickname;              /* server's nickname for client */
106        struct authdes_cred ad_cred;    /* storage for credential */
107        struct authdes_verf ad_verf;    /* storage for verifier */
108        struct timeval ad_timestamp;    /* timestamp sent */
109        des_block ad_xkey;              /* encrypted conversation key */
110        u_char ad_pkey[1024];           /* Server's actual public key */
111        char *ad_netid;                 /* Timehost netid */
112        char *ad_uaddr;                 /* Timehost uaddr */
113        nis_server *ad_nis_srvr;        /* NIS+ server struct */
114};
115
116AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *,
117        const des_block *, nis_server *);
118       
119/*
120 * documented version of authdes_seccreate
121 */
122/*
123        servername:     network name of server
124        win:            time to live
125        timehost:       optional hostname to sync with
126        ckey:           optional conversation key to use
127*/
128
129AUTH *
130authdes_seccreate(const char *servername, const u_int win,
131        const char *timehost, const des_block *ckey)
132{
133        u_char  pkey_data[1024];
134        netobj  pkey;
135        AUTH    *dummy;
136
137        if (! getpublickey(servername, (char *) pkey_data)) {
138                syslog(LOG_ERR,
139                    "authdes_seccreate: no public key found for %s",
140                    servername);
141                return (NULL);
142        }
143
144        pkey.n_bytes = (char *) pkey_data;
145        pkey.n_len = (u_int)strlen((char *)pkey_data) + 1;
146        dummy = authdes_pk_seccreate(servername, &pkey, win, timehost,
147            ckey, NULL);
148        return (dummy);
149}
150
151/*
152 * Slightly modified version of authdessec_create which takes the public key
153 * of the server principal as an argument. This spares us a call to
154 * getpublickey() which in the nameserver context can cause a deadlock.
155 */
156AUTH *
157authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window,
158        const char *timehost, const des_block *ckey, nis_server *srvr)
159{
160        AUTH *auth;
161        struct ad_private *ad;
162        char namebuf[MAXNETNAMELEN+1];
163
164        /*
165         * Allocate everything now
166         */
167        auth = ALLOC(AUTH);
168        if (auth == NULL) {
169                syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
170                return (NULL);
171        }
172        ad = ALLOC(struct ad_private);
173        if (ad == NULL) {
174                syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
175                goto failed;
176        }
177        ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */
178        ad->ad_timehost = NULL;
179        ad->ad_netid = NULL;
180        ad->ad_uaddr = NULL;
181        ad->ad_nis_srvr = NULL;
182        ad->ad_timediff.tv_sec = 0;
183        ad->ad_timediff.tv_usec = 0;
184        memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len);
185        if (!getnetname(namebuf))
186                goto failed;
187        ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf));
188        ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1);
189        ad->ad_servernamelen = strlen(servername);
190        ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1);
191
192        if (ad->ad_fullname == NULL || ad->ad_servername == NULL) {
193                syslog(LOG_ERR, "authdes_seccreate: out of memory");
194                goto failed;
195        }
196        if (timehost != NULL) {
197                ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1);
198                if (ad->ad_timehost == NULL) {
199                        syslog(LOG_ERR, "authdes_seccreate: out of memory");
200                        goto failed;
201                }
202                memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1);
203                ad->ad_dosync = TRUE;
204        } else if (srvr != NULL) {
205                ad->ad_nis_srvr = srvr; /* transient */
206                ad->ad_dosync = TRUE;
207        } else {
208                ad->ad_dosync = FALSE;
209        }
210        memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1);
211        memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1);
212        ad->ad_window = window;
213        if (ckey == NULL) {
214                if (key_gendes(&auth->ah_key) < 0) {
215                        syslog(LOG_ERR,
216            "authdes_seccreate: keyserv(1m) is unable to generate session key");
217                        goto failed;
218                }
219        } else {
220                auth->ah_key = *ckey;
221        }
222
223        /*
224         * Set up auth handle
225         */
226        auth->ah_cred.oa_flavor = AUTH_DES;
227        auth->ah_verf.oa_flavor = AUTH_DES;
228        auth->ah_ops = authdes_ops();
229        auth->ah_private = (caddr_t)ad;
230
231        if (!authdes_refresh(auth, NULL)) {
232                goto failed;
233        }
234        ad->ad_nis_srvr = NULL; /* not needed any longer */
235        return (auth);
236
237failed:
238        if (auth)
239                FREE(auth, sizeof (AUTH));
240        if (ad) {
241                if (ad->ad_fullname)
242                        FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
243                if (ad->ad_servername)
244                        FREE(ad->ad_servername, ad->ad_servernamelen + 1);
245                if (ad->ad_timehost)
246                        FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
247                if (ad->ad_netid)
248                        FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
249                if (ad->ad_uaddr)
250                        FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
251                FREE(ad, sizeof (struct ad_private));
252        }
253        return (NULL);
254}
255
256/*
257 * Implement the five authentication operations
258 */
259
260
261/*
262 * 1. Next Verifier
263 */     
264/*ARGSUSED*/
265static void
266authdes_nextverf(AUTH *auth __unused)
267{
268        /* what the heck am I supposed to do??? */
269}
270
271
272/*
273 * 2. Marshal
274 */
275static bool_t
276authdes_marshal(AUTH *auth, XDR *xdrs)
277{
278/* LINTED pointer alignment */
279        struct ad_private *ad = AUTH_PRIVATE(auth);
280        struct authdes_cred *cred = &ad->ad_cred;
281        struct authdes_verf *verf = &ad->ad_verf;
282        des_block cryptbuf[2]; 
283        des_block ivec;
284        int status;
285        int len;
286        rpc_inline_t *ixdr;
287
288        /*
289         * Figure out the "time", accounting for any time difference
290         * with the server if necessary.
291         */
292        (void)gettimeofday(&ad->ad_timestamp, NULL);
293        ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec;
294        ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec;
295        while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) {
296                ad->ad_timestamp.tv_usec -= USEC_PER_SEC;
297                ad->ad_timestamp.tv_sec++;
298        }
299
300        /*
301         * XDR the timestamp and possibly some other things, then
302         * encrypt them.
303         */
304        ixdr = (rpc_inline_t *)cryptbuf;
305        IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec);
306        IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec);
307        if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
308                IXDR_PUT_U_INT32(ixdr, ad->ad_window);
309                IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1);
310                ivec.key.high = ivec.key.low = 0;       
311                status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,
312                        (u_int) 2 * sizeof (des_block),
313                        DES_ENCRYPT | DES_HW, (char *)&ivec);
314        } else {
315                status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,
316                        (u_int) sizeof (des_block),
317                        DES_ENCRYPT | DES_HW);
318        }
319        if (DES_FAILED(status)) {
320                syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
321                return (FALSE);
322        }
323        ad->ad_verf.adv_xtimestamp = cryptbuf[0];
324        if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
325                ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high;
326                ad->ad_verf.adv_winverf = cryptbuf[1].key.low;
327        } else {
328                ad->ad_cred.adc_nickname = ad->ad_nickname;
329                ad->ad_verf.adv_winverf = 0;
330        }
331
332        /*
333         * Serialize the credential and verifier into opaque
334         * authentication data.
335         */
336        if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
337                len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen);
338        } else {
339                len = (1 + 1)*BYTES_PER_XDR_UNIT;
340        }
341
342        if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
343                IXDR_PUT_INT32(ixdr, AUTH_DES);
344                IXDR_PUT_INT32(ixdr, len);
345        } else {
346                ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor));
347                ATTEMPT(xdr_putint32(xdrs, &len));
348        }
349        ATTEMPT(xdr_authdes_cred(xdrs, cred));
350
351        len = (2 + 1)*BYTES_PER_XDR_UNIT;
352        if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
353                IXDR_PUT_INT32(ixdr, AUTH_DES);
354                IXDR_PUT_INT32(ixdr, len);
355        } else {
356                ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor));
357                ATTEMPT(xdr_putint32(xdrs, &len));
358        }
359        ATTEMPT(xdr_authdes_verf(xdrs, verf));
360        return (TRUE);
361}
362
363
364/*
365 * 3. Validate
366 */
367static bool_t
368authdes_validate(AUTH *auth, struct opaque_auth *rverf)
369{
370/* LINTED pointer alignment */
371        struct ad_private *ad = AUTH_PRIVATE(auth);
372        struct authdes_verf verf;
373        int status;
374        uint32_t *ixdr;
375        des_block buf;
376
377        if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) {
378                return (FALSE);
379        }
380/* LINTED pointer alignment */
381        ixdr = (uint32_t *)rverf->oa_base;
382        buf.key.high = (uint32_t)*ixdr++;
383        buf.key.low = (uint32_t)*ixdr++;
384        verf.adv_int_u = (uint32_t)*ixdr++;
385
386        /*
387         * Decrypt the timestamp
388         */
389        status = ecb_crypt((char *)&auth->ah_key, (char *)&buf,
390                (u_int)sizeof (des_block), DES_DECRYPT | DES_HW);
391
392        if (DES_FAILED(status)) {
393                syslog(LOG_ERR, "authdes_validate: DES decryption failure");
394                return (FALSE);
395        }
396
397        /*
398         * xdr the decrypted timestamp
399         */
400/* LINTED pointer alignment */
401        ixdr = (uint32_t *)buf.c;
402        verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1;
403        verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr);
404
405        /*
406         * validate
407         */
408        if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
409                 sizeof(struct timeval)) != 0) {
410                syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
411                return (FALSE);
412        }
413
414        /*
415         * We have a nickname now, let's use it
416         */
417        ad->ad_nickname = verf.adv_nickname;
418        ad->ad_cred.adc_namekind = ADN_NICKNAME;
419        return (TRUE);
420}
421
422/*
423 * 4. Refresh
424 */
425/*ARGSUSED*/
426static bool_t
427authdes_refresh(AUTH *auth, void *dummy __unused)
428{
429/* LINTED pointer alignment */
430        struct ad_private *ad = AUTH_PRIVATE(auth);
431        struct authdes_cred *cred = &ad->ad_cred;
432        int             ok;
433        netobj          pkey;
434
435        if (ad->ad_dosync) {
436                ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
437                    ad->ad_timehost, &(ad->ad_uaddr),
438                    &(ad->ad_netid));
439                if (! ok) {
440                        /*
441                         * Hope the clocks are synced!
442                         */
443                        ad->ad_dosync = 0;
444                        syslog(LOG_DEBUG,
445                            "authdes_refresh: unable to synchronize clock");
446                 }
447        }
448        ad->ad_xkey = auth->ah_key;
449        pkey.n_bytes = (char *)(ad->ad_pkey);
450        pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1;
451        if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) {
452                syslog(LOG_INFO,
453                    "authdes_refresh: keyserv(1m) is unable to encrypt session key");
454                return (FALSE);
455        }
456        cred->adc_fullname.key = ad->ad_xkey;
457        cred->adc_namekind = ADN_FULLNAME;
458        cred->adc_fullname.name = ad->ad_fullname;
459        return (TRUE);
460}
461
462
463/*
464 * 5. Destroy
465 */
466static void
467authdes_destroy(AUTH *auth)
468{
469/* LINTED pointer alignment */
470        struct ad_private *ad = AUTH_PRIVATE(auth);
471
472        FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
473        FREE(ad->ad_servername, ad->ad_servernamelen + 1);
474        if (ad->ad_timehost)
475                FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
476        if (ad->ad_netid)
477                FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
478        if (ad->ad_uaddr)
479                FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
480        FREE(ad, sizeof (struct ad_private));
481        FREE(auth, sizeof(AUTH));
482}
483
484static struct auth_ops *
485authdes_ops(void)
486{
487        static struct auth_ops ops;
488
489        /* VARIABLES PROTECTED BY ops_lock: ops */
490 
491        mutex_lock(&authdes_ops_lock);
492        if (ops.ah_nextverf == NULL) {
493                ops.ah_nextverf = authdes_nextverf;
494                ops.ah_marshal = authdes_marshal;
495                ops.ah_validate = authdes_validate;
496                ops.ah_refresh = authdes_refresh;
497                ops.ah_destroy = authdes_destroy;
498        }
499        mutex_unlock(&authdes_ops_lock);
500        return (&ops);
501}
Note: See TracBrowser for help on using the repository browser.