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

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 60b1d40, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/16 at 08:23:57

RPC(3): Import from FreeBSD

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