home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / appletalk / netatalk / afs / afskrbsrc.sit.hqx / AFS Kerberos 1.0B0 / common.c next >
Encoding:
C/C++ Source or Header  |  1991-03-08  |  27.7 KB  |  1,138 lines

  1. /*
  2.  * common routines for AFS Kerberos UAM and AFS Log re-authentication DA
  3.  */
  4. /*
  5.  * Copyright (c) 1990 Regents of The University of Michigan.
  6.  * All Rights Reserved.
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software
  9.  * and its documentation for any purpose and without fee is hereby
  10.  * granted, provided that the above copyright notice appears in all
  11.  * copies and that both that copyright notice and this permission
  12.  * notice appear in supporting documentation, and that the name of
  13.  * The University of Michigan not be used in advertising or
  14.  * publicity pertaining to distribution of the software without
  15.  * specific, written prior permission. This software is supplied as
  16.  * is without expressed or implied warranties of any kind.
  17.  *
  18.  *    ITD Research Systems
  19.  *    University of Michigan
  20.  *    535 W. William Street
  21.  *    Ann Arbor, Michigan
  22.  *    +1-313-936-2652
  23.  *    netatalk@terminator.cc.umich.edu
  24.  */
  25. #include    <types.h>
  26. #include    <resources.h>
  27. #include    <quickdraw.h>
  28. #include    <dialogs.h>
  29. #include    <memory.h>
  30. #include    <osutils.h>
  31. #include    <strings.h>
  32. #include    <files.h>
  33. #include    <appletalk.h>
  34. #include    <toolutils.h>
  35. #include    <fonts.h>
  36. #include    <errors.h>
  37. #include    <cursorctl.h>
  38.  
  39. /*
  40.  * MIT Kerberos and DES stuff
  41.  */
  42. #include    <des.h>
  43. #include    <krb.h>
  44. #include    <conf.h>
  45. #include    <prot.h>
  46.  
  47. #include    "uam.h"
  48.  
  49. pascal Boolean        passwdfilter();
  50.  
  51. char         afp_server[ 257 ];        /* global server name */
  52. char        afp_zone[34];            /* global zone name */
  53.  
  54. int
  55. dologin( initial, doalerts, alpp, name, passwd, srefnum, rsesskey )
  56.     short            initial;        /* true if first login */
  57.     short            doalerts;
  58.     AFPLoginPrm        *alpp;
  59.     Str255            name;
  60.     char            *passwd;
  61.     short            *srefnum;
  62.     des_cblock        rsesskey;
  63. {    
  64.     des_cblock        sesskey, pkey;
  65.     des_key_schedule    ks;
  66.     char            *mem, *recv, *send, *realm;
  67.     char            *p, *q;
  68.     short            rc, clen;
  69.     Handle            hdl;
  70.     unsigned char        tktlen, authlen;
  71.  
  72.     /*
  73.      * allocate large buffers on the heap since our stack is tiny
  74.      */
  75.     if (( mem = NewPtrClear( RECV_SIZE + SEND_SIZE + REALM_SZ + 2 )) == NULL ) {
  76.         doalert( ALRT_LOCALERR );
  77.         return( -1 );
  78.     }
  79.     send = mem;
  80.     recv = mem + SEND_SIZE;
  81.     realm = mem + SEND_SIZE + RECV_SIZE;
  82.     
  83.     /* build and send the login packet:
  84.      *
  85.      *    +-----+-----------+-------+---------------------------+
  86.      *    | CMD | \pVersion | \pUAM | \pUser[.Instance][@Realm] |
  87.      *    +-----+-----------+-------+---------------------------+
  88.      */
  89.  
  90.     p = send;
  91.     *p++ = afpLogin;
  92.     if (( hdl = Get1Resource( 'STR ', UAM_VERSION )) == NULL ) {
  93.         if ( doalerts ) doalert( ALRT_LOCALERR );
  94.         DisposPtr( mem );
  95.         return( -1 );
  96.     }
  97.     HLock( hdl );
  98.     BlockMove( (char *)*hdl, p, **hdl + 1 );
  99.     HUnlock( hdl );
  100.     p += **hdl + 1;
  101.     ReleaseResource( hdl );
  102.     
  103.     if (( hdl = Get1Resource( 'uamn', 1 )) == NULL ) {
  104.         if ( doalerts ) doalert( ALRT_LOCALERR );
  105.         DisposPtr( mem );
  106.         return( -1 );
  107.     }
  108.     HLock( hdl );
  109.     BlockMove( (char *)*hdl, p, **hdl + 1 );
  110.     HUnlock( hdl );
  111.     p += **hdl + 1;
  112.     ReleaseResource( hdl );
  113.  
  114.     BlockMove( name, p, *name + 1 );
  115.     p += *name + 1;
  116.     
  117.     alpp->cbPtr = send;
  118.     alpp->cbSize = p - send;
  119.     alpp->rbPtr = recv;
  120.     alpp->rbSize = RECV_SIZE;
  121.     alpp->ioCompletion = NULL;
  122.     
  123.     if ( initial ) {
  124.         rc = AFPCommand( (XPPParmBlkPtr)alpp, true );
  125.         if ( rc == noErr ) {
  126.             rc = wait_for_completion( (XPPParmBlkPtr)alpp );
  127.         }
  128.     } else {
  129.         alpp->sessRefnum = *srefnum;
  130.         rc = ASPUserCommand( (XPPParmBlkPtr)alpp, true );
  131.         if ( rc == noErr ) {
  132.             rc = wait_for_completion( (XPPParmBlkPtr)alpp );
  133.         }
  134.     }
  135.     if ( rc != noErr ) {
  136.         if ( doalerts ) doalert( ALRT_LOCALERR );
  137.         DisposPtr( mem );
  138.         return( -1 );
  139.     }
  140.     switch ( alpp->cmdResult ) {
  141.     case 0:
  142.     case aspServerBusy:
  143.         doalert( ALRT_NO_MORE_SESSIONS );
  144.         DisposPtr( mem );
  145.         return( -1 );
  146.     case afpAuthContinue :
  147.         break;
  148.     case afpParmErr :
  149.         if ( doalerts ) doalert( ALRT_AUTHERR );
  150.         DisposPtr( mem );
  151.         return( -1 );
  152.     case afpBadUAM :
  153.     default :
  154.         if ( doalerts ) doalert( ALRT_REMOTEERR );
  155.         DisposPtr( mem );
  156.         return( -1 );
  157.     }
  158.  
  159.     /*
  160.      * What we get back:
  161.      *
  162.      * If this is the first login attempt by the user, the packet contains both
  163.      * an application request and a ticket granting ticket.  Since Kerberos
  164.      * messages contain a type byte, we can use that to tell if we have been
  165.      * given an ApplReq.
  166.      *
  167.      *    +---------+-----+
  168.      *    | ApplReq | TGT |
  169.      *    +---------+-----+
  170.      *
  171.      * If the server and user have already negotiated a session key (stored in
  172.      * the 'skey' resource), the packet will only contain a TGT:
  173.      *
  174.      *    +-----+
  175.      *    | TGT |
  176.      *    +-----+
  177.      *
  178.      * One problem is that the user has no way of knowing what realm(s) the
  179.      * server may share with the user.  If the user attempts to use a realm
  180.      * during the initial authentication that the server does not support, then
  181.      * a ParamErr is returned by the server.
  182.      */
  183.     p = recv;
  184.     if ( *p++ != KRB_PROT_VERSION ) {
  185.         if ( doalerts ) doalert( ALRT_REMOTEERR );
  186.         DisposPtr( mem );
  187.         return( -1 );
  188.     }
  189.     if (( *p & 0xfe ) == AUTH_MSG_APPL_REQUEST ) {
  190.         p += 2;
  191.         
  192.         bzero( realm, REALM_SZ + 1 );
  193.         strncpy( realm+1, p, REALM_SZ );
  194.         lncase( realm+1, REALM_SZ );
  195.         strncpy( realm+1, p, REALM_SZ );
  196.         lncase( realm+1, REALM_SZ );
  197.         *realm = strlen( realm + 1 );
  198.         ParamText( realm, NULL, NULL, NULL );
  199.         while ( *p++ )
  200.             ;
  201.         tktlen = *p++;
  202.         authlen = *p++;
  203.         Andrew_StringToKey( passwd, realm + 1, pkey );
  204.         des_key_sched( pkey, ks );
  205.         des_pcbc_encrypt( p, p, tktlen, ks, &pkey, DES_DECRYPT );
  206.         q = p;
  207.         p += tktlen + authlen;
  208.         q++;
  209.         if ( strcmp( q, "afpserver" ) != 0 ) {    /* check principal */
  210.             if ( doalerts ) doalert( ALRT_REALMERR );
  211.             DisposPtr( mem );
  212.             return( -1 );
  213.         }
  214.         while ( *q++ )
  215.             ;
  216.         if ( strcmp( q, afp_server + 1 ) != 0 ) {    /* check instance */
  217.             if ( doalerts ) doalert( ALRT_REALMERR );
  218.             DisposPtr( mem );
  219.             return( -1 );
  220.         }
  221.         while ( *q++ )
  222.             ;
  223.         while ( *q++ )        /* Skip the realm */
  224.             ;
  225.         q += 4;            /* skip afp server's ip address */
  226.         
  227.         BlockMove( q, sesskey, sizeof( des_cblock ) );
  228.  
  229.         /* save the session key under resource id == session refnum
  230.         */
  231.         if (( hdl = Get1Resource( 'skey', alpp->sessRefnum )) != NULL ) {
  232.             RmveResource( hdl );
  233.             DisposHandle( hdl );
  234.         }
  235.         if ( PtrToHand( q, &hdl, sizeof( des_cblock )) != noErr ) {
  236.             if ( doalerts ) doalert( ALRT_LOCALERR );
  237.             DisposPtr( mem );
  238.             return( -1 );
  239.         }
  240.         AddResource( hdl, 'skey', alpp->sessRefnum, "\p" );
  241.         if ( ResError() != noErr ) {
  242.             if ( doalerts ) doalert( ALRT_LOCALERR );
  243.             DisposPtr( mem );
  244.             return( -1 );
  245.         }
  246.         WriteResource( hdl );
  247.         if ( ResError() != noErr ) {
  248.             if ( doalerts ) doalert( ALRT_LOCALERR );
  249.             DisposPtr( mem );
  250.             return( -1 );
  251.         }
  252.         ReleaseResource( hdl );
  253.  
  254.         if ( *p++ != KRB_PROT_VERSION ) {
  255.             if ( doalerts ) doalert( ALRT_REMOTEERR );
  256.             DisposPtr( mem );
  257.             return( -1 );
  258.         }
  259.  
  260.     } else if ( get_sesskey( alpp->sessRefnum, sesskey ) != 0 ) {
  261.         if ( doalerts ) doalert( ALRT_LOCALERR );
  262.         DisposPtr( mem );
  263.         return( -1 );
  264.         }
  265.     
  266.     if (( *p & 0xfe ) != AUTH_MSG_KDC_REPLY ) {
  267.         if ( doalerts ) doalert( ALRT_REMOTEERR );
  268.         DisposPtr( mem );
  269.         return( -1 );
  270.     }
  271.     /*
  272.      * the tgt is of the form (the cipher is encrypted under the user's key):
  273.      *
  274.      *   +-------------+----------------------+--------+------------+--------+
  275.      *   | krb version | msg type (kdc reply) | realm  | cipher len | cipher |
  276.      *   +-------------+----------------------+--------+------------+--------+
  277.      */
  278.     if (( *p++ & 1 ) != MSB_FIRST ) {    /* incorrect byte order */
  279.         if ( doalerts ) doalert( ALRT_LOCALERR );
  280.         DisposPtr( mem );
  281.         return( -1 );
  282.     }
  283.  
  284.     bzero( realm, REALM_SZ + 1 );    /* save realm for string to key */
  285.     strncpy( realm + 1, p, REALM_SZ );
  286.     lncase( realm + 1, REALM_SZ );
  287.     *realm = strlen( realm + 1 );
  288.     ParamText( realm, NULL, NULL, NULL );
  289.     while ( *p++ )
  290.         ;
  291.     BlockMove( p, (char *)&clen, sizeof( short ));
  292.     p += sizeof( short );
  293.     
  294.     Andrew_StringToKey( passwd, realm + 1, &pkey );
  295.     bzero( passwd, strlen( passwd ));
  296.     des_key_sched( pkey, ks );
  297.     des_pcbc_encrypt( p, p, clen, ks, &pkey, DES_DECRYPT );
  298.     if ( strcmp( "krbtgt", p + 8 ) != 0 ) {
  299.         if ( doalerts ) doalert( ALRT_REALMERR );
  300.         DisposPtr( mem );
  301.         return( -1 );
  302.     }
  303.     
  304. /* Send the next command packet.  The CMD is AFPContLogin and the cipher is returned
  305.  * re-encrypted under the session key:
  306.  *
  307.  *    +-----+---+------------+--------+
  308.  *    | CMD | 0 | cipher len | cipher |
  309.  *    +-----+---+------------+--------+
  310.  */
  311.      q = send;
  312.     *q++ = afpContLogin;
  313.     *q++ = 0;
  314.     BlockMove( (char*)&clen, q, sizeof( short ));
  315.     q += sizeof( short);
  316.     des_key_sched( sesskey, ks );
  317.     des_pcbc_encrypt( p, q, clen, ks, &sesskey, DES_ENCRYPT );
  318.     q += clen;
  319.     alpp->cbPtr = send;
  320.     alpp->cbSize = q - send;
  321.     alpp->rbPtr = recv;
  322.     alpp->rbSize = RECV_SIZE;
  323.     rc = AFPCommand( (XPPParmBlkPtr)alpp, true );
  324.     if ( rc == noErr ) {
  325.         rc = wait_for_completion( (XPPParmBlkPtr)alpp );
  326.     }
  327.     DisposPtr( mem );
  328.  
  329.     if ( rc != noErr ) {
  330.         if ( doalerts ) doalert( ALRT_LOCALERR );
  331.         return( -1 );
  332.     }
  333.     
  334.     switch ( alpp->cmdResult ) {
  335.     case noErr :
  336.         break;
  337.     case afpParmErr :
  338.         if ( doalerts ) doalert( ALRT_REALMERR );
  339.         return( -1 );
  340.     case afpBadUAM :
  341.     default :
  342.         if ( doalerts ) doalert( ALRT_REMOTEERR );
  343.         return( -1 );
  344.     }
  345.     
  346.     *srefnum = alpp->sessRefnum;
  347.     bcopy( sesskey, rsesskey, sizeof( des_cblock ));
  348.     return( noErr );
  349. }
  350.  
  351.  
  352. short
  353. wait_for_completion( xppp )
  354.     XPPParmBlkPtr    xppp;
  355. {
  356.     EventRecord    er;
  357.     long        count, ticks;
  358.     
  359.     ShowCursor();
  360.     
  361.     for( count = 0; xppp->XPP.ioResult == 1; ++count ) {
  362.         RotateCursor( count );
  363.         GetNextEvent( keyDownMask, &er );
  364.         if ( er.what == keyDown && (( er.modifiers & cmdKey ) &&
  365.                 (( er.message & charCodeMask ) == '.' ))) {
  366.             return( -1 );
  367.         }
  368.         Delay( 1L, &ticks );
  369.     }
  370.     return( noErr );
  371. }
  372.  
  373.  
  374. struct passwd_info {
  375.     char    *pwinfo_passwd;
  376.     short    pwinfo_dlogitem;
  377.     short    pwinfo_maxlen;
  378. };
  379.  
  380.  
  381. DialogPtr
  382. passwddialog( name, passwd, iconhdl, dlogid, in_uam, curr_srefnum, dosetpw )
  383.     char        *name;
  384.     char        *passwd;
  385.     Handle        iconhdl;
  386.     short        in_uam;
  387.     short        curr_srefnum;    /* see setpw() routine */
  388.     Boolean        dosetpw;    /* does the server support set password? */
  389. {
  390.     DialogPtr        dlog;
  391.     short            item, itemtype, h, v;
  392.     Boolean            ok_enabled;
  393.     Handle            ihdl;
  394.     long            len;
  395.     StringHandle        version_str;
  396.     Rect            irect, iconrect;
  397.     Str255            pstr;
  398.     TEPtr            tep;
  399.     struct passwd_info    passwds[ 2 ];
  400.     
  401.     if (( version_str = GetString( VERSION_STR )) == NULL ) {
  402.         doalert( ALRT_LOCALERR );
  403.         return( NULL );
  404.     }
  405.     
  406.     placewindow( 'DLOG', dlogid );
  407.     if (( dlog = GetNewDialog( dlogid, (Ptr)NULL, (WindowPtr)-1 )) == NULL ) {
  408.         doalert( ALRT_LOCALERR );
  409.         return( NULL );
  410.     }
  411.     SetPort( dlog );
  412.     if ( name[ 0 ] == 0 ) {
  413.         /*
  414.          * try to get Chooser name from system res. file
  415.          * It is a 'STR ' resource w/ id -16096 it seems....
  416.          */
  417.          if (( ihdl = (Handle)GetString( -16096 )) != NULL ) {
  418.              HLock( ihdl );
  419.             len = **ihdl;
  420.             if ( len > MAXNAMELEN ) {
  421.                 len = MAXNAMELEN;
  422.             }
  423.             bcopy( (char *)(*ihdl + 1), name + 1, len );
  424.             name[ 0 ] = len;
  425.          }
  426.     }
  427.     if ( name[ 0 ] != 0 ) {
  428.         GetDItem( dlog, DLOG_NAMEBOX, &itemtype, &ihdl, &irect );
  429.         SetIText( ihdl, name );
  430.         SelIText( dlog, DLOG_PASSWDBOX, 0, 1 );
  431.         enablebutton( dlog, DLOG_OK, true, true );
  432.         ok_enabled = true;
  433.     } else {
  434.         enablebutton( dlog, DLOG_OK, false, true );
  435.         ok_enabled = false;
  436.     }
  437.     enablebutton( dlog, DLOG_SETPASSWD, dosetpw && ok_enabled, false );
  438.  
  439.     if ( in_uam ) {
  440.         GetDItem( dlog, DLOG_GUEST, &itemtype, &ihdl, &irect );
  441.         SetDItem( dlog, DLOG_GUEST, itemtype | itemDisable, ihdl, &irect );
  442.         SetCtlValue( (ControlHandle)ihdl, 0 );
  443.         HiliteControl( (ControlHandle)ihdl, 255 );
  444.         GetDItem( dlog, DLOG_REGUSER, &itemtype, &ihdl, &irect );
  445.         SetDItem( dlog, DLOG_REGUSER, itemtype | itemDisable, ihdl, &irect );
  446.         SetCtlValue( (ControlHandle)ihdl, 1 );
  447.     }
  448.         
  449.     if ( iconhdl != NULL ) {
  450.         iconrect.top = 8;
  451.         iconrect.left = 21;
  452.         iconrect.bottom = 40;
  453.         iconrect.right = 53;
  454.         PlotIcon( &iconrect, iconhdl );
  455.     }
  456.     TextFont( monaco );
  457.     TextSize( 9 );
  458.     HLock( version_str );
  459.     h = dlog->portRect.right - 2 - StringWidth( *version_str );
  460.     v = dlog->portRect.bottom;
  461.     MoveTo( h, v );
  462.     DrawString( *version_str );
  463.     
  464.     passwds[ 0 ].pwinfo_passwd = passwd;
  465.     passwds[ 0 ].pwinfo_dlogitem = DLOG_PASSWDBOX;
  466.     passwds[ 0 ].pwinfo_maxlen = MAXPASSWDLEN;
  467.     passwds[ 1 ].pwinfo_passwd = NULL;
  468.     ((WindowPeek)dlog)->refCon = (char *)passwds;
  469.     
  470.     do {
  471.         ModalDialog( (ModalFilterProcPtr)passwdfilter, &item );
  472.         
  473.         if ( ((DialogPeek)dlog)->editField == DLOG_NAMEBOX - 1 ) {
  474.             tep = *(((DialogPeek)dlog)->textH);
  475.             if ( ok_enabled && tep->teLength < 1 ) {
  476.                 enablebutton( dlog, DLOG_OK, false, true );
  477.                 enablebutton( dlog, DLOG_SETPASSWD, false, false );
  478.                 ok_enabled = false;
  479.             } else if ( !ok_enabled && tep->teLength >= 1 ) {
  480.                 enablebutton( dlog, DLOG_OK, true, true );
  481.                 enablebutton( dlog, DLOG_SETPASSWD, dosetpw, false );
  482.                 ok_enabled = true;
  483.             }
  484.         }
  485.         
  486.         if ( item == DLOG_SETPASSWD ) {
  487.             /*
  488.              * call set password routine
  489.              */
  490.             GetDItem( dlog, DLOG_NAMEBOX, &itemtype, &ihdl, &irect );
  491.             GetIText( ihdl, pstr );
  492.             setpw( pstr, curr_srefnum );
  493.             
  494.             /*
  495.              * re-draw non-dialog items (since they might have been erased)
  496.              */
  497.             if ( iconhdl != NULL ) {
  498.                 PlotIcon( &iconrect, iconhdl );
  499.             }
  500.             TextFont( monaco );
  501.             TextSize( 9 );
  502.             MoveTo( h, v );
  503.             DrawString( *version_str );
  504.             enablebutton( dlog, DLOG_OK, ok_enabled, true );
  505.             enablebutton( dlog, DLOG_SETPASSWD, ok_enabled && dosetpw, false );
  506.         }
  507.  
  508.     } while ( item != DLOG_OK && item != DLOG_CANCEL );
  509.     
  510.     HUnlock( version_str );
  511.     if ( item == DLOG_CANCEL ) {
  512.         DisposDialog( dlog );
  513.         return( NULL );
  514.     }
  515.     
  516.     /* 
  517.      * get the name and null-terminate the passwd string
  518.      */
  519.     GetDItem( dlog, DLOG_NAMEBOX, &itemtype, &ihdl, &irect );
  520.     GetIText( ihdl, pstr );
  521.     BlockMove( pstr, name, pstr[ 0 ] + 1 );
  522.     
  523.     GetDItem( dlog, DLOG_PASSWDBOX, &itemtype, &ihdl, &irect );
  524.     GetIText( ihdl, pstr );
  525.     passwd[ pstr[ 0 ] ] = '\0';
  526.     HideDItem( dlog, DLOG_OK );
  527.     HideDItem( dlog, DLOG_SETPASSWD );
  528.     HideDItem( dlog, DLOG_CANCEL );
  529.     return( dlog );
  530. }
  531.  
  532.  
  533. pascal Boolean
  534. passwdfilter( dlog, event, item )
  535.     DialogPtr    dlog;
  536.     EventRecord    *event;
  537.     short        *item;
  538. {
  539.     int            i, j;
  540.     char            c;
  541.     TEPtr            tep;
  542.     struct passwd_info    *passwd;
  543.     short            type;
  544.     Handle            hdl;
  545.     Rect            r;
  546.     
  547.     if (  event->what == keyDown || event->what == autoKey ) {
  548.         c = event->message & charCodeMask;
  549.  
  550.         if ( c == CHAR_ENTER || c == CHAR_RETURN ) {
  551.             GetDItem( dlog, DLOG_OK, &type, &hdl, &r );
  552.             *item = ( type & itemDisable ) ? 0 : DLOG_OK;
  553.             return( true );
  554.         }
  555.         if ( c == CHAR_ESC ) {
  556.             *item = DLOG_CANCEL;
  557.             return( true );
  558.         }
  559.         
  560.         for ( passwd = (struct passwd_info *)((WindowPeek)dlog)->refCon;
  561.                 passwd->pwinfo_passwd != NULL;
  562.                 ++passwd ) {
  563.             if ( ((DialogPeek)dlog)->editField == passwd->pwinfo_dlogitem - 1 ) {
  564.                 break;
  565.             }
  566.         }
  567.         
  568.         if ( passwd->pwinfo_passwd == NULL ) {
  569.             /*
  570.              * must be in name entry item
  571.              */
  572.             if ( c > CHAR_MAXCTRL ) {
  573.                 tep = *(((DialogPeek)dlog)->textH);
  574.                 if ( tep->selStart >= tep->selEnd 
  575.                         && (*(((DialogPeek)dlog)->textH))->teLength > MAXNAMELEN ) {
  576.                     SysBeep( 0 );
  577.                     return( true );
  578.                 }
  579.             }
  580.             return( false );
  581.         }
  582.         
  583.         if ( c != CHAR_DELETE && c <= CHAR_MAXCTRL ) {
  584.             return( false );
  585.         }
  586.         
  587.         tep = *(((DialogPeek)dlog)->textH);
  588.         if ( tep->selStart < tep->selEnd ) {
  589.             for ( i = tep->selStart, j = tep->selEnd; i < tep->selEnd; ++i, ++j ) {
  590.                 passwd->pwinfo_passwd[ i ] = passwd->pwinfo_passwd[ j ];
  591.             }
  592.         } else if ( c != CHAR_DELETE && tep->teLength >= passwd->pwinfo_maxlen ) {
  593.             SysBeep( 0 );
  594.             return( true );
  595.         }
  596.         
  597.         if ( c != CHAR_DELETE ) {
  598.             passwd->pwinfo_passwd[ tep->selStart ] = c;
  599.             event->message &= ( !charCodeMask | !keyCodeMask );
  600.             event->message |= CHARMASK_BULLET | KEYMASK_BULLET;
  601.         }
  602.     }
  603.     return( false );
  604. }
  605.  
  606.  
  607.     
  608.     
  609. void
  610. setpw( name, curr_srefnum )
  611.     char        *name;        /* P-string */
  612.     short        curr_srefnum;    /* if zero, we need to establish a connection */
  613. {
  614.     short            rc, len, clen, srefnum, cmd_result;
  615.     char            oldpw[ MAXPASSWDLEN + 1 ], oldpwsave[ MAXPASSWDLEN + 1 ];
  616.     char            newpw[ MAXPASSWDLEN + 1 ], abuf, *buf, *p, *q;
  617.     Boolean            success, already_connected;
  618.     XPPParamBlock        xpp;
  619.     des_cblock        sesskey;
  620.     des_key_schedule    ks;
  621.     AddrBlock        addr;
  622.     DialogPtr        dlp;
  623.     GrafPtr            saveport;
  624.  
  625.     /*
  626.      * open the AppleTalk driver
  627.      */
  628.     bzero( (char*)&xpp, sizeof( XPPParamBlock ));
  629.     if ( OpenXPP( &xpp.XPP.ioRefNum ) != noErr ) {
  630.         doalert( ALRT_LOCALERR );
  631.         return;
  632.     }
  633.     
  634.     already_connected = ( curr_srefnum != 0 );
  635.     
  636.     /*
  637.      * if we are not already connected, lookup server address
  638.      */
  639.     if ( !already_connected && lookup_address( afp_server, NBPTYPE_AFP,
  640.             afp_zone, &addr ) != 0 ) {
  641.         return;
  642.     }
  643.     
  644.     success = false;
  645.     GetPort( &saveport );
  646.         
  647.     while ( !success ) {
  648.         /*
  649.          * perform password set dialog to get old and new passwords
  650.          */
  651.         if (( dlp = setpwdialog( name, oldpw, newpw )) == NULL ) {
  652.             SetPort( saveport );
  653.             return;
  654.         }
  655.         strcpy( oldpwsave, oldpw );
  656.     
  657.         /*
  658.          * set up for ASP calls
  659.          */
  660.         ParamText( afp_server, NULL, NULL, NULL );
  661.         xpp.XPP.aspTimeout = 3;    /* kind of arbitrary */
  662.         xpp.XPP.ioCompletion = NULL;
  663.         
  664.         if ( already_connected ) {
  665.             xpp.XPP.sessRefnum = curr_srefnum;
  666.             if ( get_sesskey( curr_srefnum, sesskey ) != 0 ) {
  667.                 DisposDialog( dlp );
  668.                 SetPort( saveport );
  669.                 doalert( ALRT_LOCALERR );
  670.                 return;
  671.             }
  672.         } else {
  673.             xpp.LOGIN.afpAddrBlock = addr;
  674.             xpp.LOGIN.afpAttnRoutine = NULL;
  675.             xpp.LOGIN.afpSCBPtr = NewPtrSysClear( scbMemSize );
  676.     
  677.             /*
  678.              * call our login routine to log us in (we can't do the
  679.              * change password call until we log in to the server)
  680.              */
  681.  
  682.             if ( dologin( true, false, &xpp, name, oldpw, &srefnum, sesskey ) != 0 ) {
  683.                 /*
  684.                  * on error, send logout command (just in case)
  685.                  */
  686.                 abuf = afpLogout;
  687.                 xpp.XPP.cbPtr = &abuf;
  688.                 xpp.XPP.cbSize = 1;
  689.                 if( AFPCommand( &xpp, true ) == noErr ) {
  690.                     wait_for_completion( &xpp );
  691.                 }
  692.                 DisposPtr( xpp.LOGIN.afpSCBPtr );
  693.                 doalert( ALRT_OLDPWERR );
  694.                 DisposDialog( dlp );
  695.                 continue;
  696.             }
  697.         }
  698.  
  699.         ParamText( name, NULL, NULL, NULL );
  700.  
  701.         /*
  702.          * send the afs_changepw command packet:
  703.          *    +-----+---------------------------+------------+--------+
  704.          *    | CMD | \pUser[.Instance][@Realm] | cipher len | cipher |
  705.          *    +-----+---------------------------+------------+--------+
  706.          * where cipher is the following encrypted using the session key:
  707.          *      +---------------+---------------+----------------------------+
  708.          *      | \pOldPassword | \pNewPassword | padding to 8 byte multiple |
  709.          *      +---------------+---------------+----------------------------+
  710.          */
  711.         clen = strlen( oldpwsave ) + strlen( newpw ) + 2;
  712.         if ( clen % 8 != 0 ) {
  713.             len = clen / 8;
  714.             clen = 8 * ( len + 1 );
  715.         }
  716.         xpp.XPP.cbSize = name[ 0 ] + 2 + clen + sizeof( short );
  717.         if (( buf = NewPtrClear( xpp.XPP.cbSize )) == NULL ) {
  718.             if ( !already_connected ) DisposPtr( xpp.LOGIN.afpSCBPtr );
  719.             DisposDialog( dlp );
  720.             SetPort( saveport );
  721.             doalert( ALRT_LOCALERR );
  722.             return;
  723.         }
  724.         p = xpp.XPP.cbPtr = buf;
  725.         *p++ = AFP_AFSCHANGEPW;
  726.         bcopy( name, p, name[ 0 ] + 1 );
  727.         p += name[ 0 ] + 1;
  728.         bcopy( (char *)&clen, p, sizeof( short ));
  729.         p += sizeof( short );
  730.         q = p;
  731.         len = *p++ = strlen( oldpwsave );
  732.         bcopy( oldpwsave, p, len );
  733.         p += len;
  734.         len = *p++ = strlen( newpw );
  735.         bcopy( newpw, p, len );
  736.         p += len;
  737.         des_key_sched( sesskey, ks );
  738.         des_pcbc_encrypt( q, q, clen, ks, &sesskey, DES_ENCRYPT );
  739.  
  740.         xpp.XPP.rbPtr = 0;
  741.         xpp.XPP.rbSize = NULL;
  742.         rc = ASPUserCommand( &xpp, true );
  743.         if ( rc == noErr ) {
  744.             rc = wait_for_completion( &xpp );
  745.         }
  746.         bzero( oldpwsave, strlen( oldpwsave ));
  747.         bzero( newpw, strlen( newpw ));
  748.         cmd_result = xpp.XPP.cmdResult;
  749.         success = ( rc == 0 && cmd_result == 0 );
  750.     
  751.         /*
  752.          * if we weren't connected before, send logout command (whether we
  753.          * succeeded or not!)
  754.          */
  755.         if ( !already_connected ) {
  756.             buf[ 0 ] = afpLogout;
  757.             xpp.XPP.cbSize = 1;
  758.             if ( AFPCommand( &xpp, true ) == noErr ) {
  759.                 wait_for_completion( &xpp );
  760.             }
  761.             DisposPtr( xpp.LOGIN.afpSCBPtr );
  762.         }
  763.  
  764.         DisposPtr( buf );
  765.             
  766.         if ( !success ) {
  767.             if ( rc == 0 && cmd_result == afpCallNotSupported ) {
  768.                 doalert( ALRT_SETPWNOTSUPP );
  769.             } else if ( rc == 0 && cmd_result == afpUserNotAuth ) {
  770.                 doalert( ALRT_OLDPWERR );
  771.             } else {
  772.                 doalert( ALRT_SETPWERR );
  773.             }
  774.             DisposDialog( dlp );
  775.             continue;
  776.         }
  777.     }
  778.     
  779.     ParamText( name, NULL, NULL, NULL );
  780.     DisposDialog( dlp );
  781.     SetPort( saveport );
  782.     doalert( ALRT_SETPWOK );
  783.     return;
  784. }
  785.  
  786.  
  787. DialogPtr
  788. setpwdialog( name, oldpw, newpw )
  789.     char    *name;            /* P-string */
  790.     char    *oldpw, *newpw;        /* must be each MAXPASSWDLEN + 1 in size */
  791. {
  792.     GrafPtr            saveport;
  793.     DialogPtr        dlp;
  794.     TEPtr            tep;
  795.     Boolean            ok_enabled;
  796.     Handle            hdl;
  797.     Rect            r;
  798.     Str255            ps;
  799.     short            item, type, oldpwlen, newpwlen, newpwlen1, passwds_entered;
  800.     struct passwd_info    passwds[ 3 ];
  801.     char            newpwconfirm[ MAXPASSWDLEN + 1 ];
  802.  
  803.     GetPort( &saveport );
  804.     ParamText( name, NULL, NULL, NULL );
  805.     placewindow( 'DLOG', SETPW_DLOG );
  806.     if (( dlp = GetNewDialog( SETPW_DLOG, (Ptr)NULL, (WindowPtr)-1 )) == NULL ) {
  807.         doalert( ALRT_LOCALERR );
  808.         return( NULL );
  809.     }
  810.     SetPort( dlp );
  811.     passwds_entered = 0;
  812.     ok_enabled = false;
  813.     enablebutton( dlp, DLOG_OK, false, true );
  814.     oldpwlen = newpwlen = 0;
  815.     passwds[ 0 ].pwinfo_passwd = oldpw;
  816.     passwds[ 0 ].pwinfo_dlogitem = DLOG_OLDPW;
  817.     passwds[ 1 ].pwinfo_passwd = newpw;
  818.     passwds[ 1 ].pwinfo_dlogitem = DLOG_NEWPW;
  819.     passwds[ 0 ].pwinfo_maxlen = passwds[ 1 ].pwinfo_maxlen = MAXPASSWDLEN;
  820.     passwds[ 2 ].pwinfo_passwd = NULL;
  821.     *newpw = *oldpw = *newpwconfirm = '\0';
  822.     ((WindowPeek)dlp)->refCon = (char *)passwds;
  823.     passwds_entered = 0;
  824.     
  825.     while( passwds_entered < 2 ) {
  826.         do {
  827.             ModalDialog( (ModalFilterProcPtr)passwdfilter, &item );
  828.             
  829.             tep = *(((DialogPeek)dlp)->textH);
  830.             if ( ((DialogPeek)dlp)->editField == DLOG_OLDPW - 1 ) {
  831.                 oldpwlen = tep->teLength;
  832.             } else {
  833.                 newpwlen = tep->teLength;
  834.             }
  835.             if ( ok_enabled && ( newpwlen < MINPASSWDLEN || oldpwlen < MINPASSWDLEN )) {
  836.                 enablebutton( dlp, DLOG_OK, false, true );
  837.                 ok_enabled = false;
  838.             } else if ( !ok_enabled && ( newpwlen >= MINPASSWDLEN &&
  839.                     oldpwlen >= MINPASSWDLEN )) {
  840.                 enablebutton( dlp, DLOG_OK, true, true );
  841.                 ok_enabled = true;
  842.             }
  843.             
  844.         } while ( item != DLOG_OK && item != DLOG_CANCEL );
  845.         
  846.         if ( item == DLOG_CANCEL ) {
  847.             DisposDialog( dlp );
  848.             SetPort( saveport );
  849.             return( NULL );
  850.         }
  851.         
  852.         if ( ++passwds_entered == 1 ) {
  853.             newpwlen1 = newpwlen;
  854.             newpwlen = 0;
  855.             GetDItem( dlp, DLOG_NEWPW_TEXT, &type, &hdl, &r );
  856.             SetIText( hdl, "\pReenter New Password:" );
  857.             *newpwconfirm = '\0';
  858.             GetDItem( dlp, DLOG_NEWPW, &type, &hdl, &r );
  859.             SetIText( hdl, "\p" );
  860.             SelIText( dlp, DLOG_NEWPW, 0, 1 );
  861.             GetDItem( dlp, DLOG_OLDPW, &type, &hdl, &r );
  862.             type = statText;
  863.             SetDItem( dlp, DLOG_OLDPW, type, hdl, &r );
  864.             r.top -= 4;
  865.             r.left -= 4;
  866.             r.bottom += 4;
  867.             r.right += 4;
  868.             EraseRect( &r );
  869.             InvalRect( &r );
  870.             passwds[ 1 ].pwinfo_passwd = newpwconfirm;
  871.             DrawDialog( dlp );
  872.             enablebutton( dlp, DLOG_OK, false, true );
  873.             ok_enabled = false;
  874.         } else {
  875.             oldpw[ oldpwlen ] = '\0';
  876.             newpw[ newpwlen1 ] = '\0';
  877.             newpwconfirm[ newpwlen ] = '\0';
  878.             GetDItem( dlp, DLOG_NEWPW_TEXT, &type, &hdl, &r );
  879.             SetIText( hdl, "\p              New Password:" );
  880.  
  881.             if ( strcmp( newpw, newpwconfirm ) != 0 ) {        
  882.                 doalert( ALRT_PWMISMATCH );
  883.                 passwds[ 1 ].pwinfo_passwd = newpw;
  884.                 *oldpw = *newpw = '\0';
  885.                 oldpwlen = newpwlen = 0;
  886.                 GetDItem( dlp, DLOG_OLDPW, &type, &hdl, &r );
  887.                 SetIText( hdl, "\p" );
  888.                 type = editText;
  889.                 SetDItem( dlp, DLOG_OLDPW, type, hdl, &r );
  890.                 GetDItem( dlp, DLOG_NEWPW, &type, &hdl, &r );
  891.                 SetIText( hdl, "\p" );
  892.                 SelIText( dlp, DLOG_OLDPW, 0, 0 );
  893.                 passwds_entered = 0;
  894.                 enablebutton( dlp, DLOG_OK, false, true );
  895.                 ok_enabled = false;
  896.             }
  897.         }
  898.     }
  899.     HideDItem( dlp, DLOG_OK );
  900.     HideDItem( dlp, DLOG_CANCEL );
  901.     return( dlp );
  902. }
  903.  
  904.  
  905. short
  906. lookup_address( obj, type, zone, addrp )
  907.     char        *obj;    /* p-string */
  908.     char        *type;    /* p-string */
  909.     char        *zone;    /* p-string */
  910.     AddrBlock    *addrp;
  911. {    
  912. /*
  913.  * do an NBP Lookup on obj/type/zone, return result in addrp (non-zero return code if error)
  914.  * note: AppleTalk must be loaded (open .XPP) before calling this routine
  915.  */
  916.     EntityName        en;
  917.     ATNBPRecHandle        abhdl;
  918.     short            rc, count;
  919.     char            *buf;
  920.     
  921.     bcopy( obj, en.objStr, obj[ 0 ] + 1 );
  922.     bcopy( type, en.typeStr, type[ 0 ] + 1 );
  923.     bcopy( zone, en.zoneStr, zone[ 0 ] + 1 );
  924.     if (( abhdl = (ATNBPRecHandle)NewHandle( sizeof( ATNBPRec ))) == NULL ||
  925.         ( buf = NewPtr( 256 )) == NULL ) {
  926.         doalert( ALRT_LOCALERR );
  927.         return( -1 );
  928.     }
  929.     HLock( (Handle)abhdl );
  930.     (*abhdl)->nbpEntityPtr = &en;
  931.     (*abhdl)->nbpBufPtr = buf;
  932.     (*abhdl)->nbpBufSize = 256;
  933.     (*abhdl)->nbpDataField = 1;
  934.     (*abhdl)->nbpRetransmitInfo.retransInterval = 10;    /* a little over a second */
  935.     (*abhdl)->nbpRetransmitInfo.retransCount = 5;
  936.     rc = NBPLookup( abhdl, false );
  937.     count = (*abhdl)->nbpDataField;
  938.     if ( rc == noErr && count == 1 ) {
  939.         rc = NBPExtract( buf, count, 1, &en, addrp );
  940.     }
  941.     
  942.     HUnlock( (Handle)abhdl );
  943.     DisposPtr( buf );
  944.     DisposHandle( (Handle)abhdl );
  945.     if ( rc != noErr || count != 1) {
  946.         doalert( ALRT_REMOTEERR );
  947.         return( -1 );
  948.     }
  949.     
  950.     return( 0 );
  951. }
  952.  
  953.  
  954. short
  955. get_server_status( iorefnum, addr, iconhdlp, supports_setpwp )
  956.     short        iorefnum;    /* from .XPP open */
  957.     AddrBlock    addr;
  958.     Handle        *iconhdlp;
  959.     Boolean        *supports_setpwp;
  960. {
  961. /*
  962.  * do an ASP get status network call to server at "addr" and return handle to the server's
  963.  * icon (if available)
  964.  * note: AppleTalk must be loaded (open .XPP) before calling this routine
  965.  */
  966.     XPPPrmBlk    xpp;
  967.     char        *buf;
  968.     short        off, flags;
  969.  
  970.     if (( buf = NewPtr( 1000 )) == NULL ) {
  971.         doalert( ALRT_LOCALERR );
  972.         return( -1 );
  973.     }
  974.  
  975.     xpp.ioRefNum = iorefnum;
  976.     xpp.aspTimeout = 3;
  977.     xpp.aspRetry = 3;
  978.     bcopy( (char *)&addr, (char *)&xpp.cbSize, sizeof( long ));
  979.     xpp.rbPtr = buf;
  980.     xpp.rbSize = 1000;
  981.     if ( ASPGetStatus( (XPPParmBlkPtr)&xpp, false ) != noErr ) {
  982.         doalert( ALRT_REMOTEERR );
  983.         DisposPtr( buf );
  984.         return( -1 );
  985.     }
  986.         
  987.     bcopy( buf + 6, (char *)&off, sizeof( short ));
  988.     if ( off != 0 ) {
  989.         *iconhdlp = NewHandle( 128 );
  990.         HLock( *iconhdlp );
  991.         bcopy( buf + off, (char *)**iconhdlp, 128 );
  992.         HUnlock( *iconhdlp );
  993.     } else {
  994.         *iconhdlp == NULL;
  995.     }
  996.     bcopy( buf + 8, (char *)&flags, sizeof( short ));
  997.     *supports_setpwp = flags & AFPSRVRINFO_PASSWD;
  998.     DisposPtr( buf );
  999.     return( 0 );
  1000. }
  1001.  
  1002.  
  1003. short
  1004. get_sesskey( srefnum, sesskey )
  1005.     short        srefnum;
  1006.     des_cblock    sesskey;
  1007. {
  1008. /*
  1009.  * retrieve the session key from res. file
  1010.  * return non-zero if can't get the key)
  1011.  */
  1012.      Handle    hdl;
  1013.  
  1014.     if (( hdl = Get1Resource( 'skey', srefnum )) == NULL ||
  1015.             SizeResource( hdl ) != 8 ) {
  1016.         return( -1 );
  1017.     }
  1018.     HLock( hdl );
  1019.     BlockMove( *hdl, sesskey, sizeof( des_cblock ));
  1020.     HUnlock( hdl );
  1021.     ReleaseResource( hdl );
  1022.     return( 0 );
  1023. }
  1024.  
  1025.  
  1026. void
  1027. enablebutton( dp, button, enable, frame )
  1028.     DialogPtr    dp;
  1029.     short        button;
  1030.     Boolean        enable, frame;
  1031. {
  1032.     PenState    pstate;
  1033.     short        type;
  1034.     Handle        hdl;
  1035.     Rect        r;
  1036.     
  1037.     GetPenState( &pstate );
  1038.     GetDItem( dp, button, &type, &hdl, &r );
  1039.     if ( enable ) {
  1040.         PenPat( qd.black );
  1041.         type &= ~itemDisable;
  1042.         HiliteControl( (ControlHandle)hdl, 0 );
  1043.     } else {
  1044.         PenPat( qd.gray );
  1045.         type |= itemDisable;
  1046.         HiliteControl( (ControlHandle)hdl, 255 );
  1047.     }
  1048.     SetDItem( dp, button, type, hdl, &r );
  1049.     if ( frame ) {
  1050.         InsetRect( &r, -4, -4 );
  1051.         PenSize( 3, 3 );
  1052.         FrameRoundRect( &r, 16, 16 );
  1053.     }
  1054.     SetPenState( &pstate );
  1055. }
  1056.  
  1057.  
  1058. void
  1059. doalert( alert )
  1060.     short    alert;
  1061. {
  1062.     InitCursor();
  1063.     placewindow( 'ALRT', alert );
  1064.     NoteAlert( alert, (ModalFilterProcPtr)NULL );
  1065. }
  1066.  
  1067.  
  1068. void
  1069. lncase( q, n )
  1070.     char    *q;
  1071.     int    n;
  1072. {
  1073.     for ( ; *q && n > 0; n--, q++ ) {
  1074.         if ( isupper( *q )) {
  1075.             *q = tolower( *q );
  1076.         }
  1077.     }
  1078. }
  1079.  
  1080.  
  1081. void
  1082. placewindow( rtype, rid )
  1083.     ResType    rtype;
  1084.     short    rid;
  1085. /*
  1086.  * set "rtype", "rid" window rectangle to be "alert" position (centered, 1/3 showing above & below)
  1087.  */
  1088. {
  1089.     Handle    hdl;
  1090.     Rect    *rp;
  1091.     short    left, top;
  1092.  
  1093.     if (( hdl = GetResource( rtype,  rid)) != NULL ) {
  1094.         rp = (Rect*) *hdl;
  1095.         left = ( qd.screenBits.bounds.right - ( rp->right - rp->left)) / 2;
  1096.         
  1097.         top = ( qd.screenBits.bounds.bottom - ( rp->bottom - rp->top)) / 3;
  1098.         
  1099.         if ( top < 41 ) {        /* magic number to allow for window border & */
  1100.             top = 41;        /* menu bar height */
  1101.         }
  1102.  
  1103.         rp->right += left - rp->left;
  1104.         rp->left = left;
  1105.         rp->bottom += top - rp->top;
  1106.         rp->top = top;
  1107.     }
  1108. }
  1109.  
  1110. void
  1111. mysetup_A5( globalmem, newA5p )
  1112.     Ptr    globalmem;
  1113.     long    *newA5p;
  1114. {
  1115.     *newA5p = (long)globalmem + A5Size() - 32;
  1116.     A5Init( *newA5p );
  1117. }
  1118.  
  1119.  
  1120. void
  1121. myrestore_A5( oldA5 )
  1122.     long    oldA5;
  1123. {
  1124.     SetA5( oldA5 );
  1125. }
  1126.  
  1127.  
  1128. void
  1129. mysetup_QD( oldA5 )
  1130. {
  1131.     /*
  1132.      * copy QuickDraw globals from old A5 space to new A5 space
  1133.      */
  1134.     BlockMove( (Ptr) (*((long *)oldA5) + sizeof( GrafPtr ) - QDSIZE), (Ptr)&qd, QDSIZE );
  1135. }
  1136.     
  1137.  
  1138.