]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/rpc/auth_des.c
Upgrade to OpenSSH 7.8p1.
[FreeBSD/FreeBSD.git] / lib / libc / rpc / auth_des.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
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)
59 static 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
72 extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *);
73 extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *);
74 extern int key_encryptsession_pk(char *, netobj *, des_block *);
75
76 extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *,
77         char **, char **);
78
79 /* 
80  * DES authenticator operations vector
81  */
82 static void     authdes_nextverf(AUTH *);
83 static bool_t   authdes_marshal(AUTH *, XDR *);
84 static bool_t   authdes_validate(AUTH *, struct opaque_auth *);
85 static bool_t   authdes_refresh(AUTH *, void *);
86 static void     authdes_destroy(AUTH *);
87
88 static struct auth_ops *authdes_ops(void);
89
90 /*
91  * This struct is pointed to by the ah_private field of an "AUTH *"
92  */
93 struct 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
114 AUTH *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
127 AUTH *
128 authdes_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  */
154 AUTH *
155 authdes_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
235 failed:
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*/
263 static void
264 authdes_nextverf(AUTH *auth __unused)
265 {
266         /* what the heck am I supposed to do??? */
267 }
268
269
270 /*
271  * 2. Marshal
272  */
273 static bool_t
274 authdes_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, 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  */
365 static bool_t
366 authdes_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*/
424 static bool_t
425 authdes_refresh(AUTH *auth, void *dummy __unused)
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  */
464 static void
465 authdes_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
482 static struct auth_ops *
483 authdes_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 }