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