home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / linux / slacksrce / d / libc / libc-4.6 / libc-4 / libc-linux / rpc / svcauth_des.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-15  |  11.9 KB  |  493 lines

  1. #if defined(LIBC_SCCS) && !defined(lint)
  2. static char sccsid[] =     "@(#)svcauth_des.c    2.2 88/08/15 4.0 RPCSRC; from 1.15 88/02/08 SMI";
  3. #endif
  4.  
  5. /*
  6.  * Copyright (c) 1988 by Sun Microsystems, Inc.
  7.  */
  8.  
  9.  
  10. /*
  11.  * svcauth_des.c, server-side des authentication
  12.  *
  13.  * We insure for the service the following:
  14.  * (1) The timestamp microseconds do not exceed 1 million.
  15.  * (2) The timestamp plus the window is less than the current time.
  16.  * (3) The timestamp is not less than the one previously
  17.  *     seen in the current session.
  18.  *
  19.  * It is up to the server to determine if the window size is
  20.  * too small .
  21.  *
  22.  */
  23.  
  24.  
  25. #include <des_crypt.h>
  26. #include <sys/param.h>
  27. #include <netinet/in.h>
  28. #include <rpc/types.h>
  29. #include <rpc/xdr.h>
  30. #include <rpc/auth.h>
  31. #include <rpc/auth_des.h>
  32. #include <rpc/svc_auth.h>
  33. #include <rpc/svc.h>
  34. #include <rpc/rpc_msg.h>
  35.  
  36.  
  37. #define debug(msg)     /*printf("svcauth_des: %s\n", msg)*/ 
  38.  
  39. extern char *strcpy();
  40.  
  41. #define USEC_PER_SEC ((u_long) 1000000L)
  42. #define BEFORE(t1, t2) timercmp(t1, t2, <)
  43.  
  44. /*
  45.  * LRU cache of conversation keys and some other useful items.
  46.  */
  47. #define AUTHDES_CACHESZ 64
  48. struct cache_entry {
  49.     des_block key;        /* conversation key */
  50.     char *rname;        /* client's name */
  51.     u_int window;        /* credential lifetime window */
  52.     struct timeval laststamp;    /* detect replays of creds */
  53.     char *localcred;    /* generic local credential */
  54. };
  55. static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */;
  56. static short *authdes_lru/* [AUTHDES_CACHESZ] */;
  57.  
  58. static void cache_init();    /* initialize the cache */
  59. static short cache_spot();    /* find an entry in the cache */
  60. static void cache_ref(/*short sid*/);    /* note that sid was ref'd */
  61.  
  62. static void invalidate();    /* invalidate entry in cache */
  63.  
  64. /*
  65.  * cache statistics 
  66.  */
  67. struct {
  68.     u_long ncachehits;    /* times cache hit, and is not replay */
  69.     u_long ncachereplays;    /* times cache hit, and is replay */
  70.     u_long ncachemisses;    /* times cache missed */
  71. } svcauthdes_stats;
  72.  
  73. /*
  74.  * Service side authenticator for AUTH_DES
  75.  */
  76. enum auth_stat
  77. _svcauth_des(rqst, msg)
  78.     register struct svc_req *rqst;
  79.     register struct rpc_msg *msg;
  80. {
  81.  
  82.     register long *ixdr;
  83.     des_block cryptbuf[2];
  84.     register struct authdes_cred *cred;
  85.     struct authdes_verf verf;
  86.     int status;
  87.     register struct cache_entry *entry;
  88.     short sid;
  89.     des_block *sessionkey;
  90.     des_block ivec;
  91.     u_int window;
  92.     struct timeval timestamp;
  93.     u_long namelen;
  94.     struct area {
  95.         struct authdes_cred area_cred;
  96.         char area_netname[MAXNETNAMELEN+1];
  97.     } *area;
  98.  
  99.     if (authdes_cache == NULL) {
  100.         cache_init();
  101.     }
  102.  
  103.     area = (struct area *)rqst->rq_clntcred;
  104.     cred = (struct authdes_cred *)&area->area_cred;
  105.  
  106.     /*
  107.      * Get the credential
  108.      */
  109.     ixdr = (long *)msg->rm_call.cb_cred.oa_base;
  110.     cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
  111.     switch (cred->adc_namekind) {
  112.     case ADN_FULLNAME:
  113.         namelen = IXDR_GET_U_LONG(ixdr);
  114.         if (namelen > MAXNETNAMELEN) {
  115.             return (AUTH_BADCRED);
  116.         }
  117.         cred->adc_fullname.name = area->area_netname;
  118.         bcopy((char *)ixdr, cred->adc_fullname.name, 
  119.             (u_int)namelen);
  120.         cred->adc_fullname.name[namelen] = 0;
  121.         ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
  122.         cred->adc_fullname.key.key.high = (u_long)*ixdr++;
  123.         cred->adc_fullname.key.key.low = (u_long)*ixdr++;
  124.         cred->adc_fullname.window = (u_long)*ixdr++;
  125.         break;
  126.     case ADN_NICKNAME:
  127.         cred->adc_nickname = (u_long)*ixdr++;
  128.         break;
  129.     default:
  130.         return (AUTH_BADCRED);    
  131.     }
  132.  
  133.     /*
  134.      * Get the verifier
  135.      */
  136.     ixdr = (long *)msg->rm_call.cb_verf.oa_base;
  137.     verf.adv_xtimestamp.key.high = (u_long)*ixdr++;
  138.     verf.adv_xtimestamp.key.low =  (u_long)*ixdr++;
  139.     verf.adv_int_u = (u_long)*ixdr++;
  140.  
  141.  
  142.     /*
  143.      * Get the conversation key
  144.       */
  145.     if (cred->adc_namekind == ADN_FULLNAME) {
  146.         sessionkey = &cred->adc_fullname.key;
  147.         if (key_decryptsession(cred->adc_fullname.name, 
  148.                        sessionkey) < 0) {
  149.             debug("decryptsessionkey");
  150.             return (AUTH_BADCRED); /* key not found */
  151.         }
  152.     } else { /* ADN_NICKNAME */    
  153.         sid = (short)cred->adc_nickname;
  154.         if (sid >= AUTHDES_CACHESZ) {
  155.             debug("bad nickname");
  156.             return (AUTH_BADCRED);    /* garbled credential */
  157.         }
  158.         sessionkey = &authdes_cache[sid].key;
  159.     }
  160.  
  161.  
  162.     /*
  163.      * Decrypt the timestamp
  164.      */
  165.     cryptbuf[0] = verf.adv_xtimestamp; 
  166.     if (cred->adc_namekind == ADN_FULLNAME) {
  167.         cryptbuf[1].key.high = cred->adc_fullname.window;
  168.         cryptbuf[1].key.low = verf.adv_winverf;
  169.         ivec.key.high = ivec.key.low = 0;    
  170.         status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
  171.             2*sizeof(des_block), DES_DECRYPT | DES_HW, 
  172.             (char *)&ivec);
  173.     } else {
  174.         status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
  175.             sizeof(des_block), DES_DECRYPT | DES_HW);
  176.     }
  177.     if (DES_FAILED(status)) {
  178.         debug("decryption failure");
  179.         return (AUTH_FAILED);    /* system error */
  180.     }
  181.  
  182.     /*
  183.      * XDR the decrypted timestamp
  184.      */
  185.     ixdr = (long *)cryptbuf;
  186.     timestamp.tv_sec = IXDR_GET_LONG(ixdr);
  187.     timestamp.tv_usec = IXDR_GET_LONG(ixdr);
  188.  
  189.     /*
  190.       * Check for valid credentials and verifiers.
  191.      * They could be invalid because the key was flushed
  192.      * out of the cache, and so a new session should begin.
  193.      * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
  194.      */
  195.     {
  196.         struct timeval current;
  197.         int nick;
  198.         int winverf;
  199.  
  200.         if (cred->adc_namekind == ADN_FULLNAME) {
  201.             window = IXDR_GET_U_LONG(ixdr);
  202.             winverf = IXDR_GET_U_LONG(ixdr);
  203.             if (winverf != window - 1) {
  204.                 debug("window verifier mismatch");
  205.                 return (AUTH_BADCRED);    /* garbled credential */
  206.             }
  207.             sid = cache_spot(sessionkey, cred->adc_fullname.name, 
  208.                 ×tamp);
  209.             if (sid < 0) {
  210.                 debug("replayed credential");
  211.                 return (AUTH_REJECTEDCRED);    /* replay */
  212.             }
  213.             nick = 0;
  214.         } else {    /* ADN_NICKNAME */
  215.             window = authdes_cache[sid].window;
  216.             nick = 1;
  217.         }
  218.  
  219.         if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) {
  220.             debug("invalid usecs");
  221.             /* cached out (bad key), or garbled verifier */
  222.             return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
  223.         }
  224.         if (nick && BEFORE(×tamp, 
  225.                    &authdes_cache[sid].laststamp)) {
  226.             debug("timestamp before last seen");
  227.             return (AUTH_REJECTEDVERF);    /* replay */
  228.         }
  229.         (void) gettimeofday(¤t, (struct timezone *)NULL);
  230.         current.tv_sec -= window;    /* allow for expiration */
  231.         if (!BEFORE(¤t, ×tamp)) {
  232.             debug("timestamp expired");
  233.             /* replay, or garbled credential */
  234.             return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
  235.         }
  236.     }
  237.  
  238.     /*
  239.      * Set up the reply verifier
  240.      */
  241.     verf.adv_nickname = (u_long)sid;
  242.  
  243.     /*
  244.      * xdr the timestamp before encrypting
  245.      */
  246.     ixdr = (long *)cryptbuf;
  247.     IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1);
  248.     IXDR_PUT_LONG(ixdr, timestamp.tv_usec);
  249.  
  250.     /*     
  251.      * encrypt the timestamp
  252.      */
  253.     status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
  254.         sizeof(des_block), DES_ENCRYPT | DES_HW);
  255.     if (DES_FAILED(status)) {
  256.         debug("encryption failure");
  257.         return (AUTH_FAILED);    /* system error */
  258.     }
  259.     verf.adv_xtimestamp = cryptbuf[0];
  260.  
  261.     /*
  262.      * Serialize the reply verifier, and update rqst
  263.      */
  264.     ixdr = (long *)msg->rm_call.cb_verf.oa_base;
  265.     *ixdr++ = (long)verf.adv_xtimestamp.key.high;
  266.     *ixdr++ = (long)verf.adv_xtimestamp.key.low;
  267.     *ixdr++ = (long)verf.adv_int_u;
  268.  
  269.     rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
  270.     rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
  271.     rqst->rq_xprt->xp_verf.oa_length = 
  272.         (char *)ixdr - msg->rm_call.cb_verf.oa_base;
  273.  
  274.     /*
  275.      * We succeeded, commit the data to the cache now and
  276.      * finish cooking the credential.
  277.      */
  278.     entry = &authdes_cache[sid];
  279.     entry->laststamp = timestamp;
  280.     cache_ref(sid);
  281.     if (cred->adc_namekind == ADN_FULLNAME) {
  282.         cred->adc_fullname.window = window;
  283.         cred->adc_nickname = (u_long)sid;    /* save nickname */
  284.         if (entry->rname != NULL) {
  285.             mem_free(entry->rname, strlen(entry->rname) + 1);
  286.         }
  287.         entry->rname = mem_alloc((u_int)strlen(cred->adc_fullname.name)
  288.                      + 1);
  289.         if (entry->rname != NULL) {
  290.             (void) strcpy(entry->rname, cred->adc_fullname.name);
  291.         } else {
  292.             debug("out of memory");
  293.         }
  294.         entry->key = *sessionkey;
  295.         entry->window = window;
  296.         invalidate(entry->localcred); /* mark any cached cred invalid */
  297.     } else { /* ADN_NICKNAME */
  298.         /*
  299.          * nicknames are cooked into fullnames
  300.          */    
  301.         cred->adc_namekind = ADN_FULLNAME;
  302.         cred->adc_fullname.name = entry->rname;
  303.         cred->adc_fullname.key = entry->key;
  304.         cred->adc_fullname.window = entry->window;
  305.     }
  306.     return (AUTH_OK);    /* we made it!*/
  307. }
  308.  
  309.  
  310. /*
  311.  * Initialize the cache
  312.  */
  313. static void
  314. cache_init()
  315. {
  316.     register int i;
  317.  
  318.     authdes_cache = (struct cache_entry *)
  319.         mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);    
  320.     bzero((char *)authdes_cache, 
  321.         sizeof(struct cache_entry) * AUTHDES_CACHESZ);
  322.  
  323.     authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ);
  324.     /*
  325.      * Initialize the lru list
  326.      */
  327.     for (i = 0; i < AUTHDES_CACHESZ; i++) {
  328.         authdes_lru[i] = i;
  329.     }
  330. }
  331.  
  332.  
  333. /*
  334.  * Find the lru victim
  335.  */
  336. static short
  337. cache_victim()
  338. {
  339.     return (authdes_lru[AUTHDES_CACHESZ-1]);
  340. }
  341.  
  342. /*
  343.  * Note that sid was referenced
  344.  */
  345. static void
  346. cache_ref(sid)
  347.     register short sid;
  348. {
  349.     register int i;
  350.     register short curr;
  351.     register short prev;
  352.  
  353.     prev = authdes_lru[0];
  354.     authdes_lru[0] = sid;
  355.     for (i = 1; prev != sid; i++) {
  356.         curr = authdes_lru[i];
  357.         authdes_lru[i] = prev;
  358.         prev = curr;
  359.     }
  360. }
  361.  
  362.  
  363. /*
  364.  * Find a spot in the cache for a credential containing
  365.  * the items given.  Return -1 if a replay is detected, otherwise
  366.  * return the spot in the cache.
  367.  */
  368. static short
  369. cache_spot(key, name, timestamp)
  370.     register des_block *key;
  371.     char *name;
  372.     struct timeval *timestamp;
  373. {
  374.     register struct cache_entry *cp;
  375.     register int i;
  376.     register u_long hi;
  377.  
  378.     hi = key->key.high;
  379.     for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) {
  380.         if (cp->key.key.high == hi && 
  381.             cp->key.key.low == key->key.low &&
  382.             cp->rname != NULL &&
  383.             bcmp(cp->rname, name, strlen(name) + 1) == 0) {
  384.             if (BEFORE(timestamp, &cp->laststamp)) {
  385.                 svcauthdes_stats.ncachereplays++;
  386.                 return (-1); /* replay */
  387.             }
  388.             svcauthdes_stats.ncachehits++;
  389.             return (i);    /* refresh */
  390.         }
  391.     }
  392.     svcauthdes_stats.ncachemisses++;
  393.     return (cache_victim());    /* new credential */
  394. }
  395.  
  396.  
  397. #if (defined(sun) || defined(vax) || defined(linux))
  398. /*
  399.  * Local credential handling stuff.
  400.  * NOTE: bsd unix dependent.
  401.  * Other operating systems should put something else here.
  402.  */
  403. #define UNKNOWN     -2    /* grouplen, if cached cred is unknown user */
  404. #define INVALID        -1     /* grouplen, if cache entry is invalid */
  405.  
  406. struct bsdcred {
  407.     short uid;        /* cached uid */
  408.     short gid;        /* cached gid */
  409.     short grouplen;    /* length of cached groups */
  410.     short groups[NGROUPS];    /* cached groups */
  411. };
  412.  
  413. /*
  414.  * Map a des credential into a unix cred.
  415.  * We cache the credential here so the application does
  416.  * not have to make an rpc call every time to interpret
  417.  * the credential.
  418.  */
  419. authdes_getucred(adc, uid, gid, grouplen, groups)
  420.     struct authdes_cred *adc;
  421.     short *uid;
  422.     short *gid;
  423.     short *grouplen;
  424.     register int *groups;
  425. {
  426.     unsigned sid;
  427.     register int i;
  428.     int i_uid;    
  429.     int i_gid;
  430.     int i_grouplen;
  431.     struct bsdcred *cred;
  432.  
  433.     sid = adc->adc_nickname;
  434.     if (sid >= AUTHDES_CACHESZ) {
  435.         debug("invalid nickname");
  436.         return (0);
  437.     }
  438.     cred = (struct bsdcred *)authdes_cache[sid].localcred;
  439.     if (cred == NULL) {
  440.         cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred));
  441.         authdes_cache[sid].localcred = (char *)cred;
  442.         cred->grouplen = INVALID;
  443.     }
  444.     if (cred->grouplen == INVALID) {
  445.         /*
  446.          * not in cache: lookup
  447.          */
  448.         if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid, 
  449.             &i_grouplen, groups))
  450.         {
  451.             debug("unknown netname");
  452.             cred->grouplen = UNKNOWN;    /* mark as lookup up, but not found */
  453.             return (0);
  454.         }
  455.         debug("missed ucred cache");
  456.         *uid = cred->uid = i_uid;
  457.         *gid = cred->gid = i_gid;
  458.         *grouplen = cred->grouplen = i_grouplen;
  459.         for (i = i_grouplen - 1; i >= 0; i--) {
  460.             cred->groups[i] = groups[i]; /* int to short */
  461.         }
  462.         return (1);
  463.     } else if (cred->grouplen == UNKNOWN) {
  464.         /*
  465.          * Already lookup up, but no match found
  466.          */    
  467.         return (0);
  468.     }
  469.  
  470.     /*
  471.      * cached credentials
  472.      */
  473.     *uid = cred->uid;
  474.     *gid = cred->gid;
  475.     *grouplen = cred->grouplen;
  476.     for (i = cred->grouplen - 1; i >= 0; i--) {
  477.         groups[i] = cred->groups[i];    /* short to int */
  478.     }
  479.     return (1);
  480. }
  481.  
  482. static void
  483. invalidate(cred)
  484.     char *cred;
  485. {
  486.     if (cred == NULL) {
  487.         return;
  488.     }
  489.     ((struct bsdcred *)cred)->grouplen = INVALID;
  490. }
  491. #endif
  492.  
  493.