Back to index

glibc  2.9
auth_des.c
Go to the documentation of this file.
00001 /*
00002  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00003  * unrestricted use provided that this legend is included on all tape
00004  * media and as a part of the software program in whole or part.  Users
00005  * may copy or modify Sun RPC without charge, but are not authorized
00006  * to license or distribute it to anyone else except as part of a product or
00007  * program developed by the user.
00008  *
00009  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00010  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00011  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00012  *
00013  * Sun RPC is provided with no support and without any obligation on the
00014  * part of Sun Microsystems, Inc. to assist in its use, correction,
00015  * modification or enhancement.
00016  *
00017  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00018  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00019  * OR ANY PART THEREOF.
00020  *
00021  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00022  * or profits or other special, indirect and consequential damages, even if
00023  * Sun has been advised of the possibility of such damages.
00024  *
00025  * Sun Microsystems, Inc.
00026  * 2550 Garcia Avenue
00027  * Mountain View, California  94043
00028  */
00029 /*
00030  * Copyright (c) 1988 by Sun Microsystems, Inc.
00031  */
00032 /*
00033  * auth_des.c, client-side implementation of DES authentication
00034  */
00035 
00036 #include <string.h>
00037 #include <rpc/des_crypt.h>
00038 #include <rpc/types.h>
00039 #include <rpc/auth.h>
00040 #include <rpc/auth_des.h>
00041 #include <rpc/xdr.h>
00042 #include <netinet/in.h>            /* XXX: just to get htonl() and ntohl() */
00043 #include <sys/socket.h>
00044 
00045 #define MILLION             1000000L
00046 #define RTIME_TIMEOUT 5            /* seconds to wait for sync */
00047 
00048 #define AUTH_PRIVATE(auth)  (struct ad_private *) auth->ah_private
00049 #define ALLOC(object_type)  (object_type *) mem_alloc(sizeof(object_type))
00050 #define FREE(ptr, size)            mem_free((char *)(ptr), (int) size)
00051 #define ATTEMPT(xdr_op)            if (!(xdr_op)) return (FALSE)
00052 
00053 #define debug(msg)          /* printf("%s\n", msg) */
00054 
00055 extern bool_t INTUSE(xdr_authdes_cred) (XDR *, struct authdes_cred *);
00056 extern bool_t INTUSE(xdr_authdes_verf) (XDR *, struct authdes_verf *);
00057 
00058 /*
00059  * DES authenticator operations vector
00060  */
00061 static void authdes_nextverf (AUTH *);
00062 static bool_t authdes_marshal (AUTH *, XDR *);
00063 static bool_t authdes_validate (AUTH *, struct opaque_auth *);
00064 static bool_t authdes_refresh (AUTH *);
00065 static void authdes_destroy (AUTH *);
00066 static bool_t synchronize (struct sockaddr *, struct rpc_timeval *)
00067      internal_function;
00068 
00069 static const struct auth_ops authdes_ops = {
00070   authdes_nextverf,
00071   authdes_marshal,
00072   authdes_validate,
00073   authdes_refresh,
00074   authdes_destroy
00075 };
00076 
00077 
00078 /*
00079  * This struct is pointed to by the ah_private field of an "AUTH *"
00080  */
00081 struct ad_private {
00082   char *ad_fullname;        /* client's full name */
00083   u_int ad_fullnamelen;             /* length of name, rounded up */
00084   char *ad_servername;              /* server's full name */
00085   u_int ad_servernamelen;   /* length of name, rounded up */
00086   uint32_t ad_window;              /* client specified window */
00087   bool_t ad_dosync;         /* synchronize? */
00088   struct sockaddr ad_syncaddr;     /* remote host to synch with */
00089   struct rpc_timeval ad_timediff;  /* server's time - client's time */
00090   uint32_t ad_nickname;            /* server's nickname for client */
00091   struct authdes_cred ad_cred;     /* storage for credential */
00092   struct authdes_verf ad_verf;     /* storage for verifier */
00093   struct rpc_timeval ad_timestamp; /* timestamp sent */
00094   des_block ad_xkey;        /* encrypted conversation key */
00095   u_char ad_pkey[1024];             /* Servers actual public key */
00096 };
00097 
00098 
00099 /*
00100  * Create the client des authentication object
00101  */
00102 AUTH *
00103 authdes_create (const char *servername, u_int window,
00104               struct sockaddr *syncaddr, des_block *ckey)
00105   /* servername - network name of server */
00106   /* window     - time to live */
00107   /* syncaddr   - optional addr of host to sync with */
00108   /* ckey       - optional conversation key to use */
00109 {
00110   char pkey_data[1024];
00111   netobj pkey;
00112 
00113   if (!getpublickey (servername, pkey_data))
00114     return NULL;
00115 
00116   pkey.n_bytes = pkey_data;
00117   pkey.n_len = strlen (pkey_data) + 1;
00118   return INTUSE(authdes_pk_create) (servername, &pkey, window, syncaddr, ckey);
00119 }
00120 
00121 AUTH *
00122 authdes_pk_create (const char *servername, netobj *pkey, u_int window,
00123                  struct sockaddr *syncaddr, des_block *ckey)
00124 {
00125   AUTH *auth;
00126   struct ad_private *ad;
00127   char namebuf[MAXNETNAMELEN + 1];
00128 
00129   /*
00130    * Allocate everything now
00131    */
00132   auth = ALLOC (AUTH);
00133   ad = ALLOC (struct ad_private);
00134 
00135   if (auth == NULL || ad == NULL)
00136     {
00137       debug ("authdes_create: out of memory");
00138       goto failed;
00139     }
00140 
00141   memset (ad, 0, sizeof (struct ad_private));
00142   memcpy (ad->ad_pkey, pkey->n_bytes, pkey->n_len);
00143   if (!getnetname (namebuf))
00144     goto failed;
00145   ad->ad_fullnamelen = RNDUP (strlen (namebuf));
00146   ad->ad_fullname = mem_alloc (ad->ad_fullnamelen + 1);
00147 
00148   ad->ad_servernamelen = strlen (servername);
00149   ad->ad_servername = mem_alloc (ad->ad_servernamelen + 1);
00150 
00151   if (ad->ad_fullname == NULL || ad->ad_servername == NULL)
00152     {
00153       debug ("authdes_create: out of memory");
00154       goto failed;
00155     }
00156 
00157   /*
00158    * Set up private data
00159    */
00160   memcpy (ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1);
00161   memcpy (ad->ad_servername, servername, ad->ad_servernamelen + 1);
00162   ad->ad_timediff.tv_sec = ad->ad_timediff.tv_usec = 0;
00163   if (syncaddr != NULL)
00164     {
00165       ad->ad_syncaddr = *syncaddr;
00166       ad->ad_dosync = TRUE;
00167     }
00168   else
00169     ad->ad_dosync = FALSE;
00170 
00171   ad->ad_window = window;
00172   if (ckey == NULL)
00173     {
00174       if (key_gendes (&auth->ah_key) < 0)
00175        {
00176          debug ("authdes_create: unable to gen conversation key");
00177          goto failed;
00178        }
00179     }
00180   else
00181     auth->ah_key = *ckey;
00182 
00183   /*
00184    * Set up auth handle
00185    */
00186   auth->ah_cred.oa_flavor = AUTH_DES;
00187   auth->ah_verf.oa_flavor = AUTH_DES;
00188   auth->ah_ops = (struct auth_ops *) &authdes_ops;
00189   auth->ah_private = (caddr_t) ad;
00190 
00191   if (!authdes_refresh (auth))
00192     goto failed;
00193 
00194   return auth;
00195 
00196 failed:
00197   if (auth != NULL)
00198     FREE (auth, sizeof (AUTH));
00199   if (ad != NULL)
00200     {
00201       if (ad->ad_fullname != NULL)
00202        FREE (ad->ad_fullname, ad->ad_fullnamelen + 1);
00203       if (ad->ad_servername != NULL)
00204        FREE (ad->ad_servername, ad->ad_servernamelen + 1);
00205       FREE (ad, sizeof (struct ad_private));
00206     }
00207   return NULL;
00208 }
00209 INTDEF(authdes_pk_create)
00210 
00211 /*
00212  * Implement the five authentication operations
00213  */
00214 
00215 
00216 /*
00217  * 1. Next Verifier
00218  */
00219 /*ARGSUSED */
00220 static void
00221 authdes_nextverf (AUTH *auth)
00222 {
00223   /* what the heck am I supposed to do??? */
00224 }
00225 
00226 
00227 
00228 /*
00229  * 2. Marshal
00230  */
00231 static bool_t
00232 authdes_marshal (AUTH *auth, XDR *xdrs)
00233 {
00234   struct ad_private *ad = AUTH_PRIVATE (auth);
00235   struct authdes_cred *cred = &ad->ad_cred;
00236   struct authdes_verf *verf = &ad->ad_verf;
00237   des_block cryptbuf[2];
00238   des_block ivec;
00239   int status;
00240   int len;
00241   register int32_t *ixdr;
00242   struct timeval tval;
00243 
00244   /*
00245    * Figure out the "time", accounting for any time difference
00246    * with the server if necessary.
00247    */
00248   __gettimeofday (&tval, (struct timezone *) NULL);
00249   ad->ad_timestamp.tv_sec = tval.tv_sec + ad->ad_timediff.tv_sec;
00250   ad->ad_timestamp.tv_usec = tval.tv_usec + ad->ad_timediff.tv_usec;
00251   if (ad->ad_timestamp.tv_usec >= MILLION)
00252     {
00253       ad->ad_timestamp.tv_usec -= MILLION;
00254       ad->ad_timestamp.tv_sec += 1;
00255     }
00256 
00257   /*
00258    * XDR the timestamp and possibly some other things, then
00259    * encrypt them.
00260    * XXX We have a real Year 2038 problem here.
00261    */
00262   ixdr = (int32_t *) cryptbuf;
00263   IXDR_PUT_INT32 (ixdr, ad->ad_timestamp.tv_sec);
00264   IXDR_PUT_INT32 (ixdr, ad->ad_timestamp.tv_usec);
00265   if (ad->ad_cred.adc_namekind == ADN_FULLNAME)
00266     {
00267       IXDR_PUT_U_INT32 (ixdr, ad->ad_window);
00268       IXDR_PUT_U_INT32 (ixdr, ad->ad_window - 1);
00269       ivec.key.high = ivec.key.low = 0;
00270       status = cbc_crypt ((char *) &auth->ah_key, (char *) cryptbuf,
00271              2 * sizeof (des_block), DES_ENCRYPT | DES_HW, (char *) &ivec);
00272     }
00273   else
00274     status = ecb_crypt ((char *) &auth->ah_key, (char *) cryptbuf,
00275                      sizeof (des_block), DES_ENCRYPT | DES_HW);
00276 
00277   if (DES_FAILED (status))
00278     {
00279       debug ("authdes_marshal: DES encryption failure");
00280       return FALSE;
00281     }
00282   ad->ad_verf.adv_xtimestamp = cryptbuf[0];
00283   if (ad->ad_cred.adc_namekind == ADN_FULLNAME)
00284     {
00285       ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high;
00286       ad->ad_verf.adv_winverf = cryptbuf[1].key.low;
00287     }
00288   else
00289     {
00290       ad->ad_cred.adc_nickname = ad->ad_nickname;
00291       ad->ad_verf.adv_winverf = 0;
00292     }
00293 
00294   /*
00295    * Serialize the credential and verifier into opaque
00296    * authentication data.
00297    */
00298   if (ad->ad_cred.adc_namekind == ADN_FULLNAME)
00299     len = ((1 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT + ad->ad_fullnamelen);
00300   else
00301     len = (1 + 1) * BYTES_PER_XDR_UNIT;
00302 
00303   if ((ixdr = xdr_inline (xdrs, 2 * BYTES_PER_XDR_UNIT)) != NULL)
00304     {
00305       IXDR_PUT_INT32 (ixdr, AUTH_DES);
00306       IXDR_PUT_U_INT32 (ixdr, len);
00307     }
00308   else
00309     {
00310       ATTEMPT (xdr_putint32 (xdrs, &auth->ah_cred.oa_flavor));
00311       ATTEMPT (xdr_putint32 (xdrs, &len));
00312     }
00313   ATTEMPT (INTUSE(xdr_authdes_cred) (xdrs, cred));
00314 
00315   len = (2 + 1) * BYTES_PER_XDR_UNIT;
00316   if ((ixdr = xdr_inline (xdrs, 2 * BYTES_PER_XDR_UNIT)) != NULL)
00317     {
00318       IXDR_PUT_INT32 (ixdr, AUTH_DES);
00319       IXDR_PUT_U_INT32 (ixdr, len);
00320     }
00321   else
00322     {
00323       ATTEMPT (xdr_putint32 (xdrs, &auth->ah_verf.oa_flavor));
00324       ATTEMPT (xdr_putint32 (xdrs, &len));
00325     }
00326   ATTEMPT (INTUSE(xdr_authdes_verf) (xdrs, verf));
00327 
00328   return TRUE;
00329 }
00330 
00331 
00332 /*
00333  * 3. Validate
00334  */
00335 static bool_t
00336 authdes_validate (AUTH *auth, struct opaque_auth *rverf)
00337 {
00338   struct ad_private *ad = AUTH_PRIVATE (auth);
00339   struct authdes_verf verf;
00340   int status;
00341   register uint32_t *ixdr;
00342 
00343   if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT)
00344     return FALSE;
00345 
00346   ixdr = (uint32_t *) rverf->oa_base;
00347   verf.adv_xtimestamp.key.high = *ixdr++;
00348   verf.adv_xtimestamp.key.low = *ixdr++;
00349   verf.adv_int_u = *ixdr++; /* nickname not XDR'd ! */
00350 
00351   /*
00352    * Decrypt the timestamp
00353    */
00354   status = ecb_crypt ((char *) &auth->ah_key, (char *) &verf.adv_xtimestamp,
00355                     sizeof (des_block), DES_DECRYPT | DES_HW);
00356 
00357   if (DES_FAILED (status))
00358     {
00359       debug ("authdes_validate: DES decryption failure");
00360       return FALSE;
00361     }
00362 
00363   /*
00364    * xdr the decrypted timestamp
00365    */
00366   ixdr = (uint32_t *) verf.adv_xtimestamp.c;
00367   verf.adv_timestamp.tv_sec = IXDR_GET_U_INT32 (ixdr) + 1;
00368   verf.adv_timestamp.tv_usec = IXDR_GET_U_INT32 (ixdr);
00369 
00370   /*
00371    * validate
00372    */
00373   if (memcmp ((char *) &ad->ad_timestamp, (char *) &verf.adv_timestamp,
00374              sizeof (struct rpc_timeval)) != 0)
00375     {
00376       debug ("authdes_validate: verifier mismatch\n");
00377       return FALSE;
00378     }
00379 
00380   /*
00381    * We have a nickname now, let's use it
00382    */
00383   ad->ad_nickname = verf.adv_nickname;
00384   ad->ad_cred.adc_namekind = ADN_NICKNAME;
00385   return TRUE;
00386 }
00387 
00388 /*
00389  * 4. Refresh
00390  */
00391 static bool_t
00392 authdes_refresh (AUTH *auth)
00393 {
00394   netobj pkey;
00395   struct ad_private *ad = AUTH_PRIVATE (auth);
00396   struct authdes_cred *cred = &ad->ad_cred;
00397 
00398   if (ad->ad_dosync && !synchronize (&ad->ad_syncaddr, &ad->ad_timediff))
00399     {
00400       /*
00401        * Hope the clocks are synced!
00402        */
00403       ad->ad_timediff.tv_sec = ad->ad_timediff.tv_usec = 0;
00404       debug ("authdes_refresh: unable to synchronize with server");
00405     }
00406   ad->ad_xkey = auth->ah_key;
00407   pkey.n_bytes = (char *) (ad->ad_pkey);
00408   pkey.n_len = strlen ((char *) ad->ad_pkey) + 1;
00409   if (key_encryptsession_pk (ad->ad_servername, &pkey, &ad->ad_xkey) < 0)
00410     {
00411       debug ("authdes_create: unable to encrypt conversation key");
00412       return FALSE;
00413     }
00414   cred->adc_fullname.key = ad->ad_xkey;
00415   cred->adc_namekind = ADN_FULLNAME;
00416   cred->adc_fullname.name = ad->ad_fullname;
00417   return TRUE;
00418 }
00419 
00420 /*
00421  * 5. Destroy
00422  */
00423 static void
00424 authdes_destroy (AUTH *auth)
00425 {
00426   struct ad_private *ad = AUTH_PRIVATE (auth);
00427 
00428   FREE (ad->ad_fullname, ad->ad_fullnamelen + 1);
00429   FREE (ad->ad_servername, ad->ad_servernamelen + 1);
00430   FREE (ad, sizeof (struct ad_private));
00431   FREE (auth, sizeof (AUTH));
00432 }
00433 
00434 /*
00435  * Synchronize with the server at the given address, that is,
00436  * adjust timep to reflect the delta between our clocks
00437  */
00438 static bool_t
00439 internal_function
00440 synchronize (struct sockaddr *syncaddr, struct rpc_timeval *timep)
00441 {
00442   struct timeval mytime;
00443   struct rpc_timeval timeout;
00444 
00445   timeout.tv_sec = RTIME_TIMEOUT;
00446   timeout.tv_usec = 0;
00447   if (rtime ((struct sockaddr_in *) syncaddr, timep, &timeout) < 0)
00448     return FALSE;
00449 
00450   __gettimeofday (&mytime, (struct timezone *) NULL);
00451   timep->tv_sec -= mytime.tv_sec;
00452   if (mytime.tv_usec > timep->tv_usec)
00453     {
00454       timep->tv_sec -= 1;
00455       timep->tv_usec += MILLION;
00456     }
00457   timep->tv_usec -= mytime.tv_usec;
00458   return TRUE;
00459 }