rpa.c
上传用户:xxcykj
上传日期:2007-01-04
资源大小:727k
文件大小:26k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /***********************************************************************
  2.   module:       rpa.c
  3.   program:      fetchmail
  4.   programmer:   Michael J. Palmer <106177.1156@compuserve.com>
  5.   date:         29 August 1997
  6.   compiler:     GCC 2.7.2
  7.   environment:  RedHat 4.0 Linux 2.0.18
  8.   description:  RPA authorisation code for POP3 client
  9.   The sole entry point is POP3_auth_rpa()
  10.  ***********************************************************************/
  11. #include  "config.h"
  12. #if defined(POP3_ENABLE) && defined(RPA_ENABLE)
  13. #include  <stdio.h>
  14. #include  <unistd.h>
  15. #include  <ctype.h>
  16. #include  <string.h> 
  17. #include  "socket.h"
  18. #include  "fetchmail.h"
  19. #include  "md5.h"
  20. #include  "i18n.h"
  21. #ifdef TESTMODE
  22. extern unsigned char line1[];
  23. extern unsigned char line2[];
  24. extern unsigned char line3[];
  25. extern int linecount;
  26. #endif
  27. #ifndef NO_PROTO
  28.   /* prototypes for internal functions */
  29.   static int  POP3_rpa_resp(unsigned char* argbuf, int socket );
  30.   static void LenAppend(unsigned char** pptr, int len);
  31.   static int  LenSkip(unsigned char** pptr, int rxlen);
  32.   static int  DecBase64(unsigned char* bufp);
  33.   static void EncBase64(unsigned char* bufp, int len);
  34.   static void ToUnicode(unsigned char** pptr, unsigned char delim,
  35. unsigned char* buf, int* plen, int conv);
  36.   static int  SetRealmService(unsigned char* bufp);
  37.   static void GenChallenge(unsigned char* buf, int len);
  38.   static int  DigestPassphrase(unsigned char* passphrase,
  39.        unsigned char* rbuf, int unicodeit);
  40.   static void CompUserResp();
  41.   static int  CheckUserAuth();
  42.   static void md5(unsigned char* in, int len, unsigned char* out);
  43. #endif
  44. /* RPA protocol definitions */
  45. #define         EARLYVER        "x01x00"  /* Earliest supp version */
  46. #define         LATEVER         "x03x00"  /* Latest supp version   */
  47. #define         HDR             0x60        /* ASN.1 SEQUENCE        */
  48. #define         MECH            "x06x09x60x86x48x01x86xF8x73x01x01"
  49. #define         FLAGS           "x00x01"  /* Mutual authentication */
  50. #define         STRMAX          128         /* Bytes in Unicode      */
  51. #define         Tsl             14          /* Timestamp bytelen     */
  52. #define         Pul             16          /* Passphrase digest len */
  53. #define         Cul             16          /* Usr challenge bytelen */
  54. #define         Rul             16          /* Usr response bytelen  */
  55. #define         Aul             16          /* User auth bytelen     */
  56. #define         Kusl            16          /* Session key bytelen   */
  57. #define         UNIPASS         1           /* 1=Unicode 0=iso8859   */
  58. #define         PS_RPA          42          /* Return code           */
  59. /* RPA authentication items */
  60. unsigned char   Cs[256];                    /* Service challenge     */
  61. int             Csl;                        /* Length of "    "      */
  62. unsigned char   Ts[Tsl+1];                  /* Timestamp incl      */
  63. unsigned char   Nu[STRMAX];                 /* Username in Unicode   */
  64. int             Nul;                        /* Length of " in bytes  */
  65. unsigned char   Ns[STRMAX];                 /* Service in Unicode    */
  66. int             Nsl;                        /* Length of " in bytes  */
  67. unsigned char   Nr[STRMAX];                 /* Realm in Unicode      */
  68. int             Nrl;                        /* Length of " in bytes  */
  69. unsigned char   Pu[Pul];                    /* Passphrase after MD5  */
  70. unsigned char   Cu[Cul];                    /* User challenge        */
  71. unsigned char   Ru[Rul];                    /* User response         */
  72. unsigned char   Au[Aul];                    /* User auth from Deity  */
  73. unsigned char   Kusu[Kusl];                 /* Obscured Session key  */
  74. unsigned char   Kus[Kusl];                  /* Session key           */
  75. /*********************************************************************
  76.   function:      POP3_auth_rpa
  77.   description:   send the AUTH RPA commands to the server, and
  78.                  get the server's response. Then progress through the
  79.                  RPA challenge/response protocol until we are
  80.                  (hopefully) granted authorisation.
  81.   arguments:
  82.     userid       user's id@realm e.g. myuserid@csi.com
  83.     passphrase   user's passphrase
  84.                  (upper lower or mixed case as the realm has chosen.
  85.                  spec allows various options :-(   )
  86.     socket       socket to which the server is connected.
  87.   return value:  zero if success, else non-zero.
  88.   calls:         SockPrintf, POP3_rpa_resp, EncBase64, DecBase64,
  89.                  LenAppend, GenChallenge
  90.   globals:       read outlevel.
  91.  *********************************************************************/
  92. int POP3_auth_rpa (unsigned char *userid, unsigned char *passphrase, int socket)
  93. {
  94.     int      ok,rxlen,verh,verl,i,rll;
  95.     unsigned char buf [POPBUFSIZE];
  96.     unsigned char *bufp;
  97.     int      status,aulin,kuslin;
  98.     char* stdec[4] = { N_("Success") ,
  99.        N_("Restricted user (something wrong with account)") ,
  100.        N_("Invalid userid or passphrase") ,
  101.        N_("Deity error") };
  102.     /* Initiate RPA authorisation */
  103.     SockPrintf(socket,"AUTH RPArn");
  104.     if (outlevel >= O_MONITOR)
  105. report(stdout, "> AUTH RPAn");
  106.     /* Create unicode user name in Nu.              */
  107.     /* Create MD5 digest of user's passphrase in Pu */
  108.     bufp = userid;
  109.     ToUnicode(&bufp, '@', Nu, &Nul, 1);  /* User (lowercase) */
  110.     DigestPassphrase(passphrase, Pu, UNIPASS);
  111.     /* Get + response from server (RPA ready) */
  112.     if ((ok = POP3_rpa_resp(buf,socket)) != 0)
  113.     {
  114. if (outlevel > O_SILENT && outlevel < O_MONITOR)
  115.     report(stdout, "%sn",buf);
  116. return(ok);
  117.     }
  118.     /* Assemble Token 1 in buf */
  119.     bufp    = buf;
  120.     *bufp++ = HDR;
  121.     LenAppend(&bufp,      17);
  122.     memcpy(bufp, MECH,    11); bufp += 11;
  123.     memcpy(bufp, EARLYVER, 2); bufp += 2;
  124.     memcpy(bufp, LATEVER,  2); bufp += 2;
  125.     memcpy(bufp, FLAGS,    2); bufp += 2;
  126.     /* Send Token 1, receive Token 2 */
  127.     EncBase64(buf, bufp-buf);
  128. #ifndef TESTMODE
  129.     SockPrintf(socket,"%srn",buf);
  130. #endif
  131.     if (outlevel >= O_MONITOR)
  132. report(stdout, "> %sn",buf);
  133.     if ((ok = POP3_rpa_resp(buf,socket)) != 0)
  134.     {
  135. if (outlevel > O_SILENT && outlevel < O_MONITOR)
  136.     report(stdout, "%sn",buf);
  137. return(ok);
  138.     }
  139.     if ((rxlen = DecBase64(buf)) == 0)
  140.     {
  141. if (outlevel > O_SILENT)
  142.     report(stderr, _("RPA token 2: Base64 decode errorn"));
  143. return(PS_RPA);
  144.     }
  145.     bufp = buf;
  146.     *(buf+rxlen) = 0;  /* Terminates realm list */
  147.     if (LenSkip(&bufp,rxlen) == 0) return(PS_RPA);
  148.     /* Interpret Token 2 */
  149.     verh = *(bufp++); verl = *(bufp++);
  150.     if (outlevel >= O_DEBUG)
  151. report(stdout, _("Service chose RPA version %d.%dn"),verh,verl);
  152.     Csl  = *(bufp++);
  153.     memcpy(Cs, bufp, Csl);
  154.     bufp += Csl;
  155.     if (outlevel >= O_DEBUG)
  156.     {
  157. report(stdout, _("Service challenge (l=%d):n"),Csl);
  158. for (i=0; i<Csl; i++)
  159.     report_build(stdout, "%02X ",Cs[i]);
  160. report_complete(stdout, "n");
  161.     }
  162.     memcpy(Ts, bufp, Tsl);
  163.     Ts[Tsl] = 0;
  164.     bufp += Tsl;
  165.     if (outlevel >= O_DEBUG)
  166. report(stdout, _("Service timestamp %sn"),Ts);
  167.     rll = *(bufp++) << 8; rll = rll | *(bufp++);
  168.     if ((bufp-buf+rll) != rxlen)
  169.     {
  170. if (outlevel > O_SILENT)
  171.     report(stderr, _("RPA token 2 length errorn"));
  172. return(PS_RPA);
  173.     }
  174.     if (outlevel >= O_DEBUG)
  175. report(stdout, _("Realm list: %sn"),bufp);
  176.     if (SetRealmService(bufp) != 0)
  177.     {
  178. if (outlevel > O_SILENT)
  179.     report(stderr, _("RPA error in service@realm stringn"));
  180. return(PS_RPA);
  181.     }
  182.     /* Assemble Token 3 in buf */
  183.     bufp      = buf;
  184.     *(bufp++) = HDR;
  185.     LenAppend(&bufp, 11+2+strlen(userid)+1+Cul+1+Rul );
  186.     memcpy(bufp, MECH, 11); bufp += 11;
  187.     *(bufp++) = 0;
  188.     *(bufp++) = strlen(userid);
  189.     memcpy(bufp,userid,strlen(userid)); bufp += strlen(userid);
  190.     GenChallenge(Cu,Cul);
  191.     *(bufp++) = Cul;
  192.     memcpy(bufp, Cu, Cul);  bufp += Cul;
  193.     CompUserResp();
  194.     *(bufp++) = Rul;
  195.     memcpy(bufp, Ru, Rul);  bufp += Rul;
  196.     /* Send Token 3, receive Token 4 */
  197.     EncBase64(buf,bufp-buf);
  198. #ifndef TESTMODE
  199.     SockPrintf(socket,"%srn",buf);
  200. #endif
  201.     if (outlevel >= O_MONITOR)
  202. report(stdout, "> %sn",buf);
  203.     if ((ok = POP3_rpa_resp(buf,socket)) != 0)
  204.     {
  205. if (outlevel > O_SILENT && outlevel < O_MONITOR)
  206.     report(stdout, "%sn",buf);
  207. return(ok);
  208.     }
  209.     if ((rxlen = DecBase64(buf)) == 0)
  210.     {
  211. if (outlevel > O_SILENT)
  212.     report(stderr, _("RPA token 4: Base64 decode errorn"));
  213. return(PS_RPA);
  214.     }
  215.     bufp = buf;
  216.     if (LenSkip(&bufp,rxlen) == 0) return(PS_RPA);
  217.     /* Interpret Token 4 */
  218.     aulin = *(bufp++);
  219.     if (outlevel >= O_DEBUG)
  220.     {
  221. report(stdout, _("User authentication (l=%d):n"),aulin);
  222. for (i=0; i<aulin; i++)
  223.     report_build(stdout, "%02X ",bufp[i]);
  224. report_complete(stdout, "n");
  225.     }
  226.     if (aulin == Aul) memcpy(Au, bufp, Aul);
  227.     bufp += aulin;
  228.     kuslin = *(bufp++);
  229.     if (kuslin == Kusl) memcpy(Kusu, bufp, Kusl); /* blinded */
  230.     bufp += kuslin;
  231.     if (verh == 3)
  232.     {
  233. status = *(bufp++);
  234. if (outlevel >= O_DEBUG)
  235.     report(stdout, _("RPA status: %02Xn"),status);
  236.     }
  237.     else status = 0;
  238.     if ((bufp - buf) != rxlen)
  239.     {
  240. if (outlevel > O_SILENT)
  241.     report(stderr, _("RPA token 4 length errorn"));
  242. return(PS_RPA);
  243.     }
  244.     if (status != 0)
  245.     {
  246. if (outlevel > O_SILENT)
  247.     if (status < 4)
  248. report(stderr, _("RPA rejects you: %sn"),_(stdec[status]));
  249.     else
  250. report(stderr, _("RPA rejects you, reason unknownn"));
  251. return(PS_AUTHFAIL);
  252.     }
  253.     if (Aul != aulin)
  254.     {
  255. report(stderr, 
  256.        _("RPA User Authentication length error: %dn"),aulin);
  257. return(PS_RPA);
  258.     }
  259.     if (Kusl != kuslin)
  260.     {
  261. report(stderr, _("RPA Session key length error: %dn"),kuslin);
  262. return(PS_RPA);
  263.     }
  264.     if (CheckUserAuth() != 0)
  265.     {
  266. if (outlevel > O_SILENT)
  267.     report(stderr, _("RPA _service_ auth fail. Spoof server?n"));
  268. return(PS_AUTHFAIL);
  269.     }
  270.     if (outlevel >= O_DEBUG)
  271.     {
  272. report(stdout, _("Session key established:n"));
  273. for (i=0; i<Kusl; i++)
  274.     report_build(stdout, "%02X ",Kus[i]);
  275. report_complete(stdout, "n");
  276.     }
  277.     /* Assemble Token 5 in buf and send (not in ver 2 though)  */
  278.     /* Version 3.0 definitely replies with +OK to this. I have */
  279.     /* no idea what sort of response previous versions gave.   */
  280.     if (verh != 2)
  281.     {
  282. bufp      = buf;
  283. *(bufp++) = HDR;
  284. LenAppend(&bufp, 1 );
  285. *(bufp++) = 0x42;
  286. EncBase64(buf,bufp-buf);
  287. #ifndef TESTMODE
  288. SockPrintf(socket,"%srn",buf);
  289. #endif
  290. if (outlevel >= O_MONITOR)
  291.     report(stdout, "> %sn",buf);
  292. if ((ok = POP3_rpa_resp(buf,socket)) != 0)
  293. {
  294.     if (outlevel > O_SILENT && outlevel < O_MONITOR)
  295. report(stdout, "%sn",buf);
  296.     return(ok);
  297. }
  298.     }
  299.     if (outlevel > O_SILENT)
  300. report(stdout, _("RPA authorisation completen"));
  301.     return(PS_SUCCESS);
  302. }
  303. /*********************************************************************
  304.   function:      POP3_rpa_resp
  305.   description:   get the server's response to an RPA action.
  306.                  Return received base64 string if successful
  307.   arguments:
  308.     argbuf       buffer to receive the string.
  309.     socket       socket to which the server is connected.
  310.   return value:  zero if okay, else return code.
  311.   calls:         SockGets
  312.   globals:       reads outlevel.
  313.  *********************************************************************/
  314. static int POP3_rpa_resp (argbuf,socket)
  315. unsigned char *argbuf;
  316. int socket;
  317. {
  318.     int ok;
  319.     char buf [POPBUFSIZE];
  320.     char *bufp;
  321.     int sockrc;
  322.     if (outlevel >= O_DEBUG)
  323. report(stdout,  _("Get responsen"));
  324. #ifndef TESTMODE
  325.     sockrc = gen_recv(socket, buf, sizeof(buf));
  326. #else
  327.     linecount++;
  328.     if (linecount == 1) strcpy(buf,line1);
  329.     if (linecount == 2) strcpy(buf,line2);
  330.     if (linecount == 3) strcpy(buf,line3);
  331. /*  report(stdout, "--> "); fflush(stderr);  */
  332. /*  scanf("%s",&buf)                         */
  333.     sockrc = PS_SUCCESS;
  334. #endif
  335.     if (sockrc == PS_SUCCESS) {
  336. bufp = buf;
  337. if ((*buf) == '+')
  338. {
  339.     bufp++;
  340. /*      if (*bufp == ' ') bufp++; */
  341.     if (argbuf != NULL)
  342. strcpy(argbuf,bufp);
  343.     ok=0;
  344. }
  345. else if (strcmp(buf,"-ERR") == 0)
  346.     ok = PS_ERROR;
  347. else ok = PS_PROTOCOL;
  348.     }
  349.     else
  350. ok = PS_SOCKET;
  351.     if (outlevel >= O_DEBUG)
  352. report(stdout,  _("Get response return %d [%s]n"), ok, buf);
  353.     buf[sockrc] = 0;
  354.     return(ok);
  355. }
  356. /*********************************************************************
  357.   function:      LenAppend
  358.   description:   Store token length encoded as per ASN.1 DER rules
  359.                  buffer pointer stepped on appropriately.
  360.                  Copes with numbers up to 32767 at least.
  361.   arguments:
  362.     buf          pointer to buffer to receive result
  363.     len          length value to encode
  364.   return value:  none
  365.   calls:         none
  366.   globals:       none
  367.  *********************************************************************/
  368. static void LenAppend(pptr,len)
  369. unsigned char **pptr;
  370. int  len;
  371. {
  372.     if (len < 0x80)
  373.     {
  374. **pptr = len; (*pptr)++;
  375.     }
  376.     else if (len < 0x100)
  377.     {
  378. **pptr = 0x81; (*pptr)++;
  379. **pptr = len;  (*pptr)++;
  380.     }
  381.     else
  382.     {
  383. **pptr = 0x82;       (*pptr)++;
  384. **pptr = len >> 8;   (*pptr)++;
  385. **pptr = len & 0xFF; (*pptr)++;
  386.     }
  387. }
  388. /*********************************************************************
  389.   function:      LenSkip
  390.   description:   Check token header, length, and mechanism, and
  391.                  skip past these.
  392.   arguments:
  393.     pptr         pointer to buffer pointer
  394.     rxlen        number of bytes after base64 decode
  395.   return value:  0 if error, else token length value
  396.   calls:         none
  397.   globals:       reads outlevel.
  398.  *********************************************************************/
  399. int LenSkip(pptr,rxlen)
  400. unsigned char **pptr;
  401. int rxlen;
  402. {
  403.     int len;
  404.     unsigned char *save;
  405.     save = *pptr;
  406.     if (**pptr != HDR)
  407.     {
  408. if (outlevel > O_SILENT)
  409.     report(stderr, _("Hdr not 60n"));
  410. return(0);
  411.     }
  412.     (*pptr)++;
  413.     if (((**pptr) & 0x80) == 0 )
  414.     {
  415. len = **pptr; (*pptr)++;
  416.     }
  417.     else if ((**pptr) == 0x81)
  418.     {
  419. len = *(*pptr+1); (*pptr) += 2;
  420.     }
  421.     else if ((**pptr) == 0x82)
  422.     {
  423. len = ((*(*pptr+1)) << 8) | *(*pptr+2);
  424. (*pptr) += 3;
  425.     }
  426.     else len = 0;
  427.     if (len==0)
  428.     {
  429. if (outlevel>O_SILENT)
  430.     report(stderr, _("Token length errorn"));
  431.     }
  432.     else if (((*pptr-save)+len) != rxlen)
  433.     {
  434. if (outlevel>O_SILENT)
  435.     report(stderr, _("Token Length %d disagrees with rxlen %dn"),len,rxlen);
  436. len = 0;
  437.     }
  438.     else if (memcmp(*pptr,MECH,11))
  439.     {
  440. if (outlevel > O_SILENT)
  441.     report(stderr, _("Mechanism field incorrectn"));
  442. len = 0;
  443.     }
  444.     else (*pptr) += 11;  /* Skip mechanism field */
  445.     return(len);
  446. }
  447. /*********************************************************************
  448.   function:      DecBase64
  449.   description:   Decode a Base64 string, overwriting the original.
  450.                  Note that result cannot be longer than input.
  451.   arguments:
  452.     bufp         buffer
  453.   return value:  0 if error, else number of bytes in decoded result
  454.   calls:         none
  455.   globals:       reads outlevel.
  456.  *********************************************************************/
  457. static int DecBase64(bufp)
  458. unsigned char *bufp;
  459. {
  460.     unsigned int   new, bits=0, cnt=0, i, part=0;
  461.     unsigned char  ch;
  462.     unsigned char* outp=bufp;
  463.     unsigned char* inp=bufp;
  464.     while((ch=*(inp++)) != 0)
  465.     {
  466. if ((ch != '=') && (ch != ' ') && (ch != 'n') && (ch != 'r'))
  467. {
  468.     if      ((ch>='A') && (ch <= 'Z'))   new = ch - 'A';
  469.     else if ((ch>='a') && (ch <= 'z'))   new = ch - 'a' + 26;
  470.     else if ((ch>='0') && (ch <= '9'))   new = ch - '0' + 52;
  471.     else if ( ch=='+'                )   new = 62;
  472.     else if ( ch=='/'                )   new = 63;
  473.     else {
  474. report(stderr,  _("dec64 error at char %d: %xn"), inp - bufp, ch);
  475. return(0);
  476.     }
  477.     part=((part & 0x3F)*64) + new;
  478.     bits += 6;
  479.     if (bits >= 8)
  480.     {
  481. bits -= 8;
  482. *outp = (part >> bits);
  483. cnt++; outp++;
  484.     }
  485. }
  486.     }
  487.     if (outlevel >= O_MONITOR)
  488.     {
  489. report(stdout, _("Inbound binary data:n"));
  490. for (i=0; i<cnt; i++)
  491. {
  492.     report_build(stdout, "%02X ",bufp[i]);
  493.     if (((i % 16)==15) || (i==(cnt-1)))
  494. report_complete(stdout, "n");
  495. }
  496.     }
  497.     return(cnt);
  498. }
  499. /*********************************************************************
  500.   function:      EncBase64
  501.   description:   Encode into Base64 string, overwriting the original.
  502.                  Note that result CAN be longer than input, the buffer
  503.                  is assumed to be big enough. Result string is
  504.                  terminated with .
  505.   arguments:
  506.     bufp         buffer
  507.     len          number of bytes in buffer (>0)
  508.   return value:  none
  509.   calls:         none
  510.   globals:       reads outlevel;
  511.  *********************************************************************/
  512. static void EncBase64(bufp,len)
  513. unsigned char *bufp;
  514. int  len;
  515. {
  516.     unsigned char* outp;
  517.     unsigned char  c1,c2,c3;
  518.     char x[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  519.     int  i;
  520.     if (outlevel >= O_MONITOR)
  521.     {
  522. report(stdout, _("Outbound data:n"));
  523. for (i=0; i<len; i++)
  524. {
  525.     report_build(stdout, "%02X ",bufp[i]);
  526.     if (((i % 16)==15) || (i==(len-1)))
  527. report_complete(stdout, "n");
  528. }
  529.     }
  530.     outp = bufp + (((len-1)/3)*4);
  531.     *(outp+4) = 0;
  532.     /* So we can do the update in place, start at the far end! */
  533.     for (i=((len-1)/3)*3; i>=0; i-=3)
  534.     {
  535. c1 = bufp[i];
  536. if ((i+1) < len) c2 = bufp[i+1]; else c2=0;
  537. if ((i+2) < len) c3 = bufp[i+2]; else c3=0;
  538. *(outp) = x[c1/4];
  539. *(outp+1) = x[((c1 & 3)*16) + (c2/16)];
  540. if ((i+1) < len) *(outp+2) = x[((c2 & 0x0F)*4) + (c3/64)];
  541. else *(outp+2) = '=';
  542. if ((i+2) < len) *(outp+3) = x[c3 & 0x3F];
  543. else *(outp+3) = '=';
  544. outp -= 4;
  545.     }
  546. }
  547. /*********************************************************************
  548.   function:      ToUnicode
  549.   description:   Convert ASCII (or iso-8859-1) byte string into
  550.                  Unicode. Ensure length isn't too long (STRMAX).
  551.   arguments:
  552.     pptr         pointer to input buffer
  553.     delim        delimiter character (in addition to )
  554.     buf          buffer where Unicode will go
  555.     plen         pointer to length variable (# bytes output)
  556.     conv         1 to convert to lowercase, 0 leaves alone
  557.   return value:  none
  558.   calls:         none
  559.   globals:       reads outlevel;
  560.  *********************************************************************/
  561. static void ToUnicode(pptr,delim,buf,plen,conv)
  562. unsigned char **pptr; /* input string  */
  563. unsigned char delim;
  564. unsigned char *buf;   /* output buffer */
  565. int  *plen;
  566. int conv;
  567. {
  568.     unsigned char *p;
  569.     int i;
  570.     *plen = 0; p=buf;
  571.     while ( ((**pptr)!=delim) && ((**pptr)!=0) && ((*plen)<STRMAX) )
  572.     {
  573. *(p++) = 0;
  574. if (conv)
  575.     *(p++) = tolower(**pptr);
  576. else
  577.     *(p++) = (**pptr);
  578. (*plen) += 2;
  579. (*pptr)++;
  580.     }
  581.     if ( ((**pptr)!=delim) && ((**pptr)!=0) && ((*plen)==STRMAX) )
  582.     {
  583. if (outlevel > O_SILENT)
  584.     report(stderr, _("RPA String too longn"));
  585. *plen = 0;
  586.     }
  587.     if (outlevel >= O_DEBUG)
  588.     {
  589. report(stdout, _("Unicode:n"));
  590. for (i=0; i<(*plen); i++)
  591. {
  592.     report_build(stdout, "%02X ",buf[i]);
  593.     if (((i % 16)==15) || (i==((*plen)-1)))
  594. report_complete(stdout, "n");
  595. }
  596.     }
  597. }
  598. /*********************************************************************
  599.   function:      SetRealmService
  600.   description:   Select a realm from list, and store it.
  601.   arguments:
  602.     bufp         pointer to buffer
  603.   return value:  none
  604.   calls:         none
  605.   globals:       reads outlevel.
  606.                  writes Ns Nsl Nr Nrl
  607.  *********************************************************************/
  608. static int SetRealmService(bufp)
  609. unsigned char* bufp;
  610. {
  611.     /* For the moment we pick the first available realm. It would */
  612.     /* make more sense to verify that the realm which the user    */
  613.     /* has given (as part of id) is in the list, and select it's  */
  614.     /* corresponding service name.                                */
  615.     ToUnicode(&bufp, '@', Ns, &Nsl, 1);  /* Service    */
  616.     bufp++;                              /* Skip the @ */
  617.     ToUnicode(&bufp, ' ', Nr, &Nrl, 1);  /* Realm name */
  618.     if ((Nrl == 0) || (Nsl == 0))
  619. return(PS_RPA);
  620.     return(0);
  621. }
  622. /*********************************************************************
  623.   function:      GenChallenge
  624.   description:   Generate a random User challenge
  625.   arguments:
  626.     buf          pointer to buffer
  627.     len          length in bytes
  628.   return value:  none
  629.   calls:         none
  630.   globals:       reads outlevel.
  631.                  reads /dev/random
  632.  *********************************************************************/
  633. static void GenChallenge(buf,len)
  634. unsigned char *buf;
  635. int  len;
  636. {
  637.     int  i;
  638.     FILE *devrandom;
  639.     devrandom = fopen("/dev/urandom","rb");
  640.     if (devrandom == NULL && outlevel > O_SILENT)
  641.     {
  642. report(stdout, _("RPA Failed open of /dev/urandom. This shouldn'tn"));
  643. report(stdout, _("    prevent you logging in, but means youn"));
  644. report(stdout, _("    cannot be sure you are talking to then"));
  645. report(stdout, _("    service that you think you are (replayn"));
  646. report(stdout, _("    attacks by a dishonest service are possible.)n"));
  647.     }
  648.     for(i=0; i<len; i++)
  649. buf[i] = devrandom ? fgetc(devrandom) : random();
  650.     if (devrandom)
  651. fclose(devrandom); /* should be safe, file mode was "r" */
  652.     if (outlevel >= O_DEBUG)
  653.     {
  654. report(stdout, _("User challenge:n"));
  655. for (i=0; i<len; i++)
  656.   {
  657.   report_build(stdout, "%02X ",buf[i]);
  658.   if (((i % 16)==15) || (i==(len-1)))
  659.     report_complete(stdout, "n");
  660.   }
  661.     }
  662. }
  663. /*********************************************************************
  664.   function:      DigestPassphrase
  665.   description:   Use MD5 to compute digest (Pu) of Passphrase
  666.                  Don't map to lower case. We assume the user is
  667.                  aware of the case requirement of the realm.
  668.                  (Why oh why have options in the spec?!)
  669.   arguments:
  670.     passphrase   buffer containing string,  terminated
  671.     rbuf         buffer into which digest goes
  672.   return value:  0 if ok, else error code
  673.   calls:         md5
  674.   globals:       reads authentication items listed above.
  675.                  writes Pu.
  676.  *********************************************************************/
  677. static int DigestPassphrase(passphrase,rbuf,unicodeit)
  678. unsigned char *passphrase;
  679. unsigned char *rbuf;
  680. int unicodeit;
  681. {
  682.     int   len;
  683.     unsigned char  workarea[STRMAX];
  684.     unsigned char* ptr;
  685.     if (unicodeit)  /* Option in spec. Yuck. */
  686.     {
  687. ptr = passphrase;
  688. ToUnicode(&ptr, '', workarea, &len, 0); /* No case conv here */
  689. if (len == 0)
  690.     return(PS_SYNTAX);
  691. ptr = workarea;
  692.     }
  693.     else
  694.     {
  695. ptr = rbuf;
  696. len = strlen(passphrase);
  697.     }
  698.     md5(ptr,len,rbuf);
  699.     return(0);
  700. }
  701. /*********************************************************************
  702.   function:      CompUserResp
  703.   description:   Use MD5 to compute User Response (Ru) from
  704.                  Pu Z(48) Nu Ns Nr Cu Cs Ts Pu
  705.   arguments:     none
  706.   return value:  none
  707.   calls:         MD5
  708.   globals:       reads authentication items listed above.
  709.                  writes Ru.
  710.  *********************************************************************/
  711. static void CompUserResp()
  712. {
  713.     unsigned char  workarea[Pul+48+STRMAX*5+Tsl+Pul];
  714.     unsigned char* p;
  715.     p = workarea;
  716.     memcpy(p , Pu,  Pul); p += Pul;
  717.     memset(p , '', 48); p += 48;
  718.     memcpy(p , Nu,  Nul); p += Nul;
  719.     memcpy(p , Ns,  Nsl); p += Nsl;
  720.     memcpy(p , Nr,  Nrl); p += Nrl;
  721.     memcpy(p , Cu,  Cul); p += Cul;
  722.     memcpy(p , Cs,  Csl); p += Csl;
  723.     memcpy(p , Ts,  Tsl); p += Tsl;
  724.     memcpy(p , Pu,  Pul); p += Pul;
  725.     md5(workarea,p-workarea,Ru);
  726. }
  727. /*********************************************************************
  728.   function:      CheckUserAuth
  729.   description:   Use MD5 to verify Authentication Response to User (Au)
  730.                  using  Pu Z(48) Ns Nu Nr Kusu Cs Cu Ts Kus Pu
  731.                  Also creates unobscured session key Kus from obscured
  732.                  one Kusu
  733.   arguments:     none
  734.   return value:  0 if ok, PS_RPA if mismatch
  735.   calls:         MD5
  736.   globals:       reads authentication items listed above.
  737.                  writes Ru.
  738.  *********************************************************************/
  739. static int CheckUserAuth()
  740. {
  741.     unsigned char  workarea[Pul+48+STRMAX*7+Tsl+Pul];
  742.     unsigned char* p;
  743.     unsigned char  md5ans[16];
  744.     int i;
  745.     /* Create unobscured Kusu */
  746.     p = workarea;
  747.     memcpy(p , Pu,  Pul); p += Pul;
  748.     memset(p , '', 48); p += 48;
  749.     memcpy(p , Ns,  Nsl); p += Nsl;
  750.     memcpy(p , Nu,  Nul); p += Nul;
  751.     memcpy(p , Nr,  Nrl); p += Nrl;
  752.     memcpy(p , Cs,  Csl); p += Csl;
  753.     memcpy(p , Cu,  Cul); p += Cul;
  754.     memcpy(p , Ts,  Tsl); p += Tsl;
  755.     memcpy(p , Pu,  Pul); p += Pul;
  756.     md5(workarea,p-workarea,md5ans);
  757.     for (i=0; i<16; i++) Kus[i] = Kusu[i] ^ md5ans[i];
  758.     /* Compute Au from our information */
  759.     p = workarea;
  760.     memcpy(p , Pu,  Pul); p += Pul;
  761.     memset(p , '', 48); p += 48;
  762.     memcpy(p , Ns,  Nsl); p += Nsl;
  763.     memcpy(p , Nu,  Nul); p += Nul;
  764.     memcpy(p , Nr,  Nrl); p += Nrl;
  765.     memcpy(p , Kusu,Kusl);p += Kusl;
  766.     memcpy(p , Cs,  Csl); p += Csl;
  767.     memcpy(p , Cu,  Cul); p += Cul;
  768.     memcpy(p , Ts,  Tsl); p += Tsl;
  769.     memcpy(p , Kus, Kusl);p += Kusl;
  770.     memcpy(p , Pu,  Pul); p += Pul;
  771.     md5(workarea,p-workarea,md5ans);
  772.     /* Compare the two */
  773.     for (i=0; i<16; i++)
  774. if (Au[i] != md5ans[i]) return(PS_RPA);
  775.     return(0);
  776. }
  777. /*********************************************************************
  778.   function:      md5
  779.   description:   Apply MD5
  780.   arguments:
  781.     in           input byte stream
  782.     len          length in bytes
  783.     out          128 bit result buffer
  784.   return value:  none
  785.   calls:         MD5 primitives
  786.   globals:       reads outlevel
  787.  *********************************************************************/
  788. static void md5(in,len,out)
  789. unsigned char*    in;
  790. int      len;
  791. unsigned char*    out;
  792. {
  793.     int      i;
  794.     MD5_CTX  md5context;
  795.     if (outlevel >= O_DEBUG)
  796.     {
  797. report(stdout, _("MD5 being applied to data block:n"));
  798. for (i=0; i<len; i++)
  799. {
  800.     report_build(stdout, "%02X ",in[i]);
  801.     if (((i % 16)==15) || (i==(len-1)))
  802. report_complete(stdout, "n");
  803. }
  804.     }
  805.     MD5Init(   &md5context );
  806.     MD5Update( &md5context, in, len );
  807.     MD5Final(  out, &md5context );
  808.     if (outlevel >= O_DEBUG)
  809.     {
  810. report(stdout, _("MD5 result is: n"));
  811. for (i=0; i<16; i++)
  812. {
  813.     report_build(stdout, "%02X ",out[i]);
  814. }
  815. report_complete(stdout, "n");
  816.     }
  817. }
  818. #endif /* POP3_ENABLE && RPA_ENABLE */
  819. /* rpa.c ends here */