freebsd-almost-working-client-20020216
[openafs.git] / src / kauth / authclient.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /* These routines provide a convenient interface to the AuthServer. */
11
12 #include <afsconfig.h>
13 #if defined(UKERNEL)
14 #include "../afs/param.h"
15 #else
16 #include <afs/param.h>
17 #endif
18
19 RCSID("$Header$");
20
21 #if defined(UKERNEL)
22 #include "../afs/sysincludes.h"
23 #include "../afs/afsincludes.h"
24 #include "../afs/afs_usrops.h"
25 #include "../afs/stds.h"
26 #include "../afs/pthread_glock.h"
27 #include "../rx/rxkad.h"
28 #include "../afs/cellconfig.h"
29 #include "../afs/ubik.h"
30 #include "../afs/auth.h"
31 #include "../des/des.h"
32 #include "../afs/afsutil.h"
33
34 #include "../afsint/kauth.h"
35 #include "../afs/kautils.h"
36 #include "../afs/pthread_glock.h"
37
38 #else /* defined(UKERNEL) */
39 #include <afs/stds.h>
40 #include <afs/pthread_glock.h>
41 #include <sys/types.h>
42 #ifdef AFS_NT40_ENV
43 #include <winsock2.h>
44 #else
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #endif
48 #ifdef HAVE_STRING_H
49 #include <string.h>
50 #else
51 #ifdef HAVE_STRINGS_H
52 #include <strings.h>
53 #endif
54 #endif
55 #include <rx/rxkad.h>
56 #include <afs/cellconfig.h>
57 #include <ubik.h>
58 #include <afs/auth.h>
59 #include <des.h>
60 #include <afs/afsutil.h>
61 #include "kauth.h"
62 #include "kautils.h"
63 #endif /* defined(UKERNEL) */
64
65
66 static struct afsconf_dir *conf = 0;
67 static struct afsconf_cell explicit_cell_server_list;
68 static struct afsconf_cell debug_cell_server_list;
69 static int explicit = 0;
70 static int debug = 0;
71
72 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
73
74 /* Copy the specified list of servers into a specially know cell named
75    "explicit".  The cell can then be used to debug experimental servers. */
76
77 void ka_ExplicitCell (
78   char *cell,
79   afs_int32 serverList[])
80 {
81     int i;
82
83     LOCK_GLOBAL_MUTEX
84     ka_ExpandCell (cell, explicit_cell_server_list.name, 0);
85     for (i=0; i<MAXHOSTSPERCELL; i++)
86         if (serverList[i]) {
87             explicit_cell_server_list.numServers = i+1;
88             explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
89             explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
90                 serverList[i];
91             explicit_cell_server_list.hostName[i][0] = 0;
92             explicit_cell_server_list.hostAddr[i].sin_port =
93                 htons(AFSCONF_KAUTHPORT);
94 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
95             explicit_cell_server_list.hostAddr[i].sin_len =
96                 sizeof(struct sockaddr_in);
97 #endif
98             explicit = 1;
99         }           
100         else break;
101     UNLOCK_GLOBAL_MUTEX
102 }
103
104 static int myCellLookup (
105   struct afsconf_dir  *conf,
106   char                *cell,
107   char                *service,
108   struct afsconf_cell *cellinfo)
109 {
110     if (debug) {
111         *cellinfo = debug_cell_server_list;
112         return 0;
113     }
114     else if (explicit && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
115         *cellinfo = explicit_cell_server_list;
116         return 0;
117     }
118     /* call the real one */
119     else return afsconf_GetCellInfo (conf, cell, service, cellinfo);
120 }
121
122 afs_int32 ka_GetServers (
123   char *cell,
124   struct afsconf_cell *cellinfo)
125 {
126     afs_int32 code;
127     char cellname[MAXKTCREALMLEN];
128
129     LOCK_GLOBAL_MUTEX
130     if (cell && !strlen(cell)) cell = 0;
131     else cell = lcstring (cellname, cell, sizeof(cellname));
132
133     if (!conf) {
134 #ifdef UKERNEL
135         conf = afs_cdir;
136 #else /* UKERNEL */
137         conf = afsconf_Open (AFSDIR_CLIENT_ETC_DIRPATH);
138 #endif /* UKERNEL */
139         if (!conf) {
140             UNLOCK_GLOBAL_MUTEX
141             return KANOCELLS;
142         }
143     }
144     code = myCellLookup (conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
145     UNLOCK_GLOBAL_MUTEX
146     return code;
147 }
148
149 afs_int32 ka_GetSecurity (
150   int   service,
151   struct ktc_token *token,
152   struct rx_securityClass **scP,
153   int  *siP)                            /* security class index */
154 {
155     LOCK_GLOBAL_MUTEX
156     *scP = 0;
157     switch (service) {
158       case KA_AUTHENTICATION_SERVICE:
159       case KA_TICKET_GRANTING_SERVICE:
160 no_security:
161         *scP = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
162         *siP = RX_SCINDEX_NULL;
163         break;
164       case KA_MAINTENANCE_SERVICE:
165         if (!token) goto no_security;
166         *scP = rxkad_NewClientSecurityObject
167             (rxkad_crypt, &token->sessionKey, token->kvno,
168              token->ticketLen, token->ticket);
169         *siP = RX_SCINDEX_KAD;
170         break;
171       default:
172         UNLOCK_GLOBAL_MUTEX
173         return KABADARGUMENT;
174     }
175     if (*scP == 0) {
176         printf ("Failed gettting security object\n");
177         UNLOCK_GLOBAL_MUTEX
178         return KARXFAIL;
179     }
180     UNLOCK_GLOBAL_MUTEX
181     return 0;
182 }
183
184 afs_int32 ka_SingleServerConn (
185   char *cell,
186   char *server,                         /* name of server to contact */
187   int   service,
188   struct ktc_token *token,
189   struct ubik_client **conn)
190 {
191     afs_int32                code;
192     struct rx_connection    *serverconns[2];
193     struct rx_securityClass *sc;
194     int                      si;        /* security class index */
195     struct afsconf_cell      cellinfo;  /* for cell auth server list */
196     int   i;
197     int   match;
198     char  sname[MAXHOSTCHARS];
199     int   snamel;
200
201     LOCK_GLOBAL_MUTEX
202     code = ka_GetServers (cell, &cellinfo);
203     if (code) {
204         UNLOCK_GLOBAL_MUTEX
205         return code;
206     }
207
208     lcstring (sname, server, sizeof(sname));
209     snamel = strlen (sname);
210     match = -1;
211     for (i=0; i<cellinfo.numServers; i++) {
212         if (strncmp (cellinfo.hostName[i], sname, snamel) == 0) {
213             if (match >= 0) {
214                 UNLOCK_GLOBAL_MUTEX
215                 return KANOCELLS;
216             }
217             else match = i;
218         }
219     }
220     if (match<0) {
221         UNLOCK_GLOBAL_MUTEX
222         return KANOCELLS;
223     }
224
225     code = rx_Init(0);
226     if (code) {
227         UNLOCK_GLOBAL_MUTEX
228         return code;
229     }
230
231     code = ka_GetSecurity (service, token, &sc, &si);
232     if (code) {
233         UNLOCK_GLOBAL_MUTEX
234         return code;
235     }
236
237 #ifdef AFS_PTHREAD_ENV
238     serverconns[0] =
239         rx_GetCachedConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
240                           cellinfo.hostAddr[match].sin_port, service, sc, si);
241 #else
242     serverconns[0] =
243         rx_NewConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
244                           cellinfo.hostAddr[match].sin_port, service, sc, si);
245 #endif
246     serverconns[1] = 0;                 /* terminate list */
247
248     /* next, pass list of server rx_connections (in serverconns), and a place
249        to put the returned client structure that we'll use in all of our rpc
250        calls (via ubik_Call) */
251     *conn = 0;
252     code = ubik_ClientInit(serverconns, conn);
253     rxs_Release (sc);
254     UNLOCK_GLOBAL_MUTEX
255     if (code) return KAUBIKINIT;
256     return 0;
257 }
258
259 afs_int32 ka_AuthSpecificServersConn (
260   int                  service,
261   struct ktc_token    *token,
262   struct afsconf_cell *cellinfo,
263   struct ubik_client **conn)
264 {
265     afs_int32                code;
266     struct rx_connection    *serverconns[MAXSERVERS];
267     struct rx_securityClass *sc;
268     int                      si;        /* security class index */
269     int                      i;
270
271     LOCK_GLOBAL_MUTEX
272     code = rx_Init(0);
273     if (code) {
274         UNLOCK_GLOBAL_MUTEX
275         return code;
276     }
277
278     code = ka_GetSecurity (service, token, &sc, &si);
279     if (code) {
280         UNLOCK_GLOBAL_MUTEX
281         return code;
282     }
283
284     for (i=0; i<cellinfo->numServers; i++)
285 #ifdef AFS_PTHREAD_ENV
286         serverconns[i] =
287             rx_GetCachedConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
288                               cellinfo->hostAddr[i].sin_port, service, sc, si);
289 #else
290         serverconns[i] =
291             rx_NewConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
292                               cellinfo->hostAddr[i].sin_port, service, sc, si);
293 #endif
294     serverconns[cellinfo->numServers] = 0; /* terminate list */
295
296     /* next, pass list of server rx_connections (in serverconns), and a place
297        to put the returned client structure that we'll use in all of our rpc
298        calls (via ubik_Call) */
299     *conn = 0;
300     code = ubik_ClientInit(serverconns, conn);
301     rxs_Release (sc);
302     UNLOCK_GLOBAL_MUTEX
303     if (code) return KAUBIKINIT;
304     return 0;
305 }
306
307 afs_int32 ka_AuthServerConn (
308   char                *cell,
309   int                  service,
310   struct ktc_token    *token,
311   struct ubik_client **conn)
312 {
313     afs_int32                code;
314     struct rx_connection    *serverconns[MAXSERVERS];
315     struct rx_securityClass *sc;
316     int                      si;        /* security class index */
317     int                      i;
318     struct afsconf_cell      cellinfo;  /* for cell auth server list */
319
320     LOCK_GLOBAL_MUTEX
321     code = ka_GetServers (cell, &cellinfo);
322     if (code) {
323         UNLOCK_GLOBAL_MUTEX
324         return code;
325     }
326
327     code = rx_Init(0);
328     if (code) {
329         UNLOCK_GLOBAL_MUTEX
330         return code;
331     }
332
333     code = ka_GetSecurity (service, token, &sc, &si);
334     if (code) {
335         UNLOCK_GLOBAL_MUTEX
336         return code;
337     }
338
339     for (i=0; i<cellinfo.numServers; i++)
340 #ifdef AFS_PTHREAD_ENV
341         serverconns[i] =
342             rx_GetCachedConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
343                               cellinfo.hostAddr[i].sin_port, service, sc, si);
344 #else
345         serverconns[i] =
346             rx_NewConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
347                               cellinfo.hostAddr[i].sin_port, service, sc, si);
348 #endif
349     serverconns[cellinfo.numServers] = 0; /* terminate list */
350
351     /* next, pass list of server rx_connections (in serverconns), and a place
352        to put the returned client structure that we'll use in all of our rpc
353        calls (via ubik_Call) */
354     *conn = 0;
355     code = ubik_ClientInit(serverconns, conn);
356     rxs_Release (sc);
357     UNLOCK_GLOBAL_MUTEX
358     if (code) return KAUBIKINIT;
359     return 0;
360 }
361
362 static afs_int32 CheckTicketAnswer(
363   ka_BBS *oanswer,
364   afs_int32 challenge,
365   struct ktc_token *token,
366   struct ktc_principal *caller, 
367   struct ktc_principal *server,
368   char *label,
369   afs_int32 *pwexpires)
370 {
371     struct ka_ticketAnswer *answer;
372     afs_uint32 cksum;
373     unsigned char tempc;
374
375     answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
376
377     cksum = ntohl(answer->cksum);
378     if (challenge != ntohl(answer->challenge)) return KABADPROTOCOL;
379     memcpy(&token->sessionKey, &answer->sessionKey, sizeof(token->sessionKey));
380     token->startTime = ntohl(answer->startTime);
381     token->endTime = ntohl(answer->endTime);
382     token->kvno = (short) ntohl(answer->kvno);
383     token->ticketLen = ntohl(answer->ticketLen);
384
385     if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0)
386         return KABADPROTOCOL;
387     if ((token->ticketLen < MINKTCTICKETLEN)||(token->ticketLen > MAXKTCTICKETLEN)) 
388       return KABADPROTOCOL;
389
390     {   char *strings = answer->name;
391         int len;
392 #undef chkstr
393 #define chkstr(field) \
394         len = strlen (strings); \
395         if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
396         if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
397         strings += len+1
398
399         if (caller) {
400             chkstr (caller->name);
401             chkstr (caller->instance);
402             chkstr (caller->cell);
403         } else { chkstr (0); chkstr (0); chkstr (0); }
404         if (server) {
405             chkstr (server->name);
406             chkstr (server->instance);
407         } else { chkstr (0); chkstr (0); }
408
409         if ( oanswer->SeqLen - 
410              ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
411              >= (ENCRYPTIONBLOCKSIZE + 12)
412            )
413           return KABADPROTOCOL;
414
415         memcpy(token->ticket, strings, token->ticketLen);
416         strings += token->ticketLen;
417         if (memcmp (strings, label, KA_LABELSIZE) != 0) return KABADPROTOCOL;
418
419         if (pwexpires) {
420           afs_int32 temp;
421           strings += KA_LABELSIZE;
422           temp = round_up_to_ebs((strings - oanswer->SeqBody));
423           
424           if (oanswer->SeqLen > temp) {
425             strings = oanswer->SeqBody + temp;
426             memcpy(&temp, strings, sizeof(afs_int32));
427             tempc = ntohl(temp) >> 24;
428             /* don't forget this if you add any more fields!
429             strings += sizeof(afs_int32);
430             */
431           }
432           else {
433             tempc = 255;
434           }
435           *pwexpires = tempc;
436         }
437
438     }
439     return 0;
440 }
441
442 /* call this instead of stub and we'll guarantee to find a host that's up.
443  * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
444  */
445 static afs_int32
446 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
447     struct ubik_client *aclient;
448     int (*aproc)();
449     afs_int32 aflags;
450     void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
451 {
452   afs_int32 code, lcode;
453   int count;
454   int pass;
455
456   /* First pass only checks servers known running. Second checks all.
457    * Once we've cycled through all the servers and still nothing, return
458    * error code from the last server tried.
459    */
460   for (pass=0, aflags |= UPUBIKONLY; pass<2; pass++, aflags &= ~UPUBIKONLY) {
461       code  = 0;
462       count = 0;
463       do {                                        /* Cycle through the servers */
464          lcode = code;
465          code = ubik_CallIter (aproc, aclient, aflags, &count, p1,p2,p3,p4,p5,p6,p7,p8);
466       } while ((code == UNOQUORUM) || (code == UNOTSYNC) || 
467                (code == KALOCKED)  || (code == -1));
468       
469       if (code != UNOSERVERS) break;
470   } 
471
472   /* If cycled through all the servers, return the last error code */
473   if ((code == UNOSERVERS) && lcode) {
474       code = lcode;
475   }
476   return code;
477 }
478
479 /* This is the interface to the AuthServer RPC routine Authenticate.  It
480    formats the request packet, calls the encryption routine on the answer,
481    calls Authenticate, and decrypts the response.  The response is checked for
482    correctness and its contents are copied into the token. */
483
484 /* Errors:
485      KABADKEY = the key failed when converted to a key schedule.  Probably bad
486        parity.
487      KAUBIKCALL - the call to Ubik returned an error, probably a communication
488        failure such as timeout.
489      KABADPROTOCOL - the returned packet was in error.  Since a packet was
490        returned it can be presumed that the AuthServer correctly interpreted
491        the response.  This may indicate an inauthentic AuthServer.
492      <other> - errors generated by the server process are returned directly.
493  */
494
495 afs_int32 ka_Authenticate (
496   char *name,
497   char *instance,
498   char *cell,
499   struct ubik_client *conn,             /* Ubik connection to the AuthServer in
500                                            the desired cell */
501   int   service,                        /* ticket granting or admin service */
502   struct ktc_encryptionKey *key,
503   Date  start,
504   Date end,                     /* ticket lifetime */
505   struct ktc_token *token,
506   afs_int32 *pwexpires)                       /* days until it expires */
507 {   
508     afs_int32  code;
509     des_key_schedule schedule;
510     Date  request_time;
511     struct ka_gettgtRequest request;
512     struct ka_gettgtAnswer answer_old;
513     struct ka_ticketAnswer answer;
514     ka_CBS arequest;
515     ka_BBS oanswer;
516     char *req_label;
517     char *ans_label;
518     int   version;
519
520     LOCK_GLOBAL_MUTEX
521     if (code = des_key_sched (key, schedule)) {
522         UNLOCK_GLOBAL_MUTEX
523         return KABADKEY;
524     }
525
526     if (service == KA_MAINTENANCE_SERVICE) {
527         req_label = KA_GETADM_REQ_LABEL;
528         ans_label = KA_GETADM_ANS_LABEL;
529     } else if (service == KA_TICKET_GRANTING_SERVICE) {
530         req_label = KA_GETTGT_REQ_LABEL;
531         ans_label = KA_GETTGT_ANS_LABEL;
532     } else {
533         UNLOCK_GLOBAL_MUTEX
534         return KABADARGUMENT;
535     }
536
537     request_time = time(0);
538     request.time = htonl(request_time);
539     memcpy(request.label, req_label, sizeof(request.label));
540     arequest.SeqLen = sizeof(request);
541     arequest.SeqBody = (char *)&request;
542     des_pcbc_encrypt (arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
543                  schedule, key, ENCRYPT);
544     
545     oanswer.MaxSeqLen = sizeof(answer);
546     oanswer.SeqLen = 0;
547     oanswer.SeqBody = (char *)&answer;
548
549     version = 2;
550     code = kawrap_ubik_Call (KAA_AuthenticateV2, conn, 0,
551                      name, instance, start, end, &arequest, &oanswer);
552     if (code == RXGEN_OPCODE) {
553         extern afs_int32 KAA_Authenticate();
554         oanswer.MaxSeqLen = sizeof(answer);
555         oanswer.SeqBody = (char *)&answer;
556         version = 1;
557         code = ubik_Call (KAA_Authenticate, conn, 0,
558                      name, instance, start, end, &arequest, &oanswer);
559         if (code == RXGEN_OPCODE) {
560             extern int KAA_Authenticate_old();
561             oanswer.MaxSeqLen = sizeof(answer_old);
562             oanswer.SeqBody = (char *)&answer_old;
563             version = 0;
564             code = ubik_Call (KAA_Authenticate_old, conn, 0,
565                               name, instance, start, end, &arequest, &oanswer);
566         }
567         if (code == RXGEN_OPCODE) {
568             code = KAOLDINTERFACE;
569         }
570     }
571     if (code) {
572         UNLOCK_GLOBAL_MUTEX
573         if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
574         return KAUBIKCALL;
575     }
576     des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
577                  schedule, key, DECRYPT);
578     
579     switch (version) {
580       case 1:
581       case 2:
582         {   struct ktc_principal caller;
583             strcpy (caller.name, name);
584             strcpy (caller.instance, instance);
585             strcpy (caller.cell, "");
586             code = CheckTicketAnswer (&oanswer, request_time+1, token,
587                                       &caller, 0, ans_label, pwexpires);
588             if (code) {
589                 UNLOCK_GLOBAL_MUTEX
590                 return code;
591             }
592         }
593         break;
594       case 0:
595         answer_old.time = ntohl(answer_old.time);
596         answer_old.ticket_len = ntohl(answer_old.ticket_len);
597         if ((answer_old.time != request_time+1) ||
598             (answer_old.ticket_len < MINKTCTICKETLEN) ||
599             (answer_old.ticket_len > MAXKTCTICKETLEN)) {
600             UNLOCK_GLOBAL_MUTEX
601             return KABADPROTOCOL;
602         }
603         {   char *label = ((char *)answer_old.ticket)+answer_old.ticket_len;
604             
605             if (strncmp(label, ans_label, sizeof(answer_old.label))) {
606                 UNLOCK_GLOBAL_MUTEX
607                 return KABADPROTOCOL;
608             }
609             token->startTime = start;
610             token->endTime = end;
611             token->kvno = ntohl(answer_old.kvno);
612             token->ticketLen = answer_old.ticket_len;
613             memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
614             memcpy(&token->sessionKey, &answer_old.sessionkey, sizeof(struct ktc_encryptionKey));
615         }
616         break;
617       default:
618         UNLOCK_GLOBAL_MUTEX
619         return KAINTERNALERROR;
620     }
621
622     UNLOCK_GLOBAL_MUTEX
623     return 0;
624 }
625
626 afs_int32 ka_GetToken (
627   char               *name,
628   char               *instance,
629   char               *cell,
630   char               *cname,
631   char               *cinst,
632   struct ubik_client *conn,             /* Ubik conn to cell's AuthServer */
633   Date                start, 
634   Date                end,      /* desired ticket lifetime */
635   struct ktc_token   *auth_token,
636   char               *auth_domain,
637   struct ktc_token   *token)
638 {
639     struct ka_getTicketTimes times;
640     struct ka_getTicketAnswer answer_old;
641     struct ka_ticketAnswer answer;
642     afs_int32  code;
643     ka_CBS aticket;
644     ka_CBS atimes;
645     ka_BBS oanswer;
646     char *strings;
647     int   len;
648     des_key_schedule schedule;
649     int   version;
650     afs_int32  pwexpires;
651
652     LOCK_GLOBAL_MUTEX
653     aticket.SeqLen = auth_token->ticketLen;
654     aticket.SeqBody = auth_token->ticket;
655
656     code = des_key_sched (&auth_token->sessionKey, schedule);
657     if (code) {
658         UNLOCK_GLOBAL_MUTEX
659         return KABADKEY;
660     }
661
662     times.start = htonl(start);
663     times.end = htonl(end);
664     des_ecb_encrypt (&times, &times, schedule, ENCRYPT);
665
666     atimes.SeqLen = sizeof(times);
667     atimes.SeqBody = (char *)&times;
668
669     oanswer.SeqLen = 0;
670     oanswer.MaxSeqLen = sizeof(answer);
671     oanswer.SeqBody = (char *)&answer;
672
673     version = 1;
674     code = ubik_Call (KAT_GetTicket, conn, 0,
675                       auth_token->kvno, auth_domain, &aticket,
676                       name, instance, &atimes, &oanswer);
677     if (code == RXGEN_OPCODE) {
678         extern int KAT_GetTicket_old ();
679         oanswer.SeqLen = 0;             /* this may be set by first call */
680         oanswer.MaxSeqLen = sizeof(answer_old);
681         oanswer.SeqBody = (char *)&answer_old;
682         version = 0;
683         code = ubik_Call (KAT_GetTicket_old, conn, 0,
684                           auth_token->kvno, auth_domain, &aticket,
685                           name, instance, &atimes, &oanswer);
686         if (code == RXGEN_OPCODE) {
687             code = KAOLDINTERFACE;
688         }
689     }
690     if (code) {
691         UNLOCK_GLOBAL_MUTEX
692         if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
693         return KAUBIKCALL;
694     }
695
696     des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
697                   schedule, &auth_token->sessionKey, DECRYPT);
698
699     switch (version) {
700       case 1:
701         {   struct ktc_principal server;
702             strcpy (server.name, name);
703             strcpy (server.instance, instance);
704             code = CheckTicketAnswer   (&oanswer, 0, token, 0, &server, 
705                                         KA_GETTICKET_ANS_LABEL, &pwexpires);
706             if (code) {
707                 UNLOCK_GLOBAL_MUTEX
708                 return code;
709             }
710         }
711         break;
712       case 0:
713         token->startTime = ntohl(answer_old.startTime);
714         token->endTime = ntohl(answer_old.endTime);
715         token->ticketLen = ntohl(answer_old.ticketLen);
716         token->kvno = ntohl(answer_old.kvno);
717         memcpy(&token->sessionKey, &answer_old.sessionKey, sizeof(token->sessionKey));
718         
719         if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0) {
720             UNLOCK_GLOBAL_MUTEX
721             return KABADPROTOCOL;
722         }
723         if ((token->ticketLen < MINKTCTICKETLEN) ||
724             (token->ticketLen > MAXKTCTICKETLEN)) {
725             UNLOCK_GLOBAL_MUTEX
726             return KABADPROTOCOL;
727         }
728         strings = answer_old.name;
729         len = strlen(strings);          /* check client name */
730         if ((len < 1) || (len > MAXKTCNAMELEN)) {
731             UNLOCK_GLOBAL_MUTEX
732             return KABADPROTOCOL;
733         }
734         strings += len+1;                       /* check client instance */
735         len = strlen(strings);
736         if ((len < 0) || (len > MAXKTCNAMELEN)) {
737             UNLOCK_GLOBAL_MUTEX
738             return KABADPROTOCOL;
739         }
740         strings += len+1;
741         len = strlen(strings);          /* check client cell */
742         if ((len < 0) || (len > MAXKTCNAMELEN)) {
743             UNLOCK_GLOBAL_MUTEX
744             return KABADPROTOCOL;
745         }
746         strings += len+1;
747         len = strlen(strings);          /* check server name */
748         if ((len < 1) || (len > MAXKTCNAMELEN) ||
749             strcmp (name, strings)) {
750             UNLOCK_GLOBAL_MUTEX
751             return KABADPROTOCOL;
752         }
753         strings += len+1;
754         len = strlen(strings);          /* check server instance */
755         if ((len < 0) || (len > MAXKTCNAMELEN) ||
756             strcmp (instance, strings)) {
757             UNLOCK_GLOBAL_MUTEX
758             return KABADPROTOCOL;
759         }
760         strings += len+1;
761
762         if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
763             ENCRYPTIONBLOCKSIZE) {
764             UNLOCK_GLOBAL_MUTEX
765             return KABADPROTOCOL;
766         }
767         memcpy(token->ticket, strings, token->ticketLen);
768         
769         break;
770       default:
771         UNLOCK_GLOBAL_MUTEX
772         return KAINTERNALERROR;
773     }
774
775     UNLOCK_GLOBAL_MUTEX
776     return 0;
777 }
778
779 afs_int32 ka_ChangePassword (
780   char               *name,
781   char               *instance,
782   struct ubik_client *conn,             /* Ubik connection to the AuthServer in
783                                            the desired cell */
784   struct ktc_encryptionKey *oldkey,
785   struct ktc_encryptionKey *newkey)
786 {
787     afs_int32      code;
788
789     LOCK_GLOBAL_MUTEX
790 #ifdef AFS_S390_LINUX20_ENV
791     code = ubik_Call_New (KAM_SetPassword, conn, 0, name, 
792                          instance, 0, 0, *newkey);
793 #else
794     code = ubik_Call_New (KAM_SetPassword, conn, 0, name, 
795                           instance, 0, *newkey);
796 #endif
797     UNLOCK_GLOBAL_MUTEX
798     return code;
799 }