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