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