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