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