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