dont-close-this-afsconf-either-20060921
[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     UNLOCK_GLOBAL_MUTEX;
149     return code;
150 }
151
152 afs_int32
153 ka_GetSecurity(int service, struct ktc_token * token,
154                struct rx_securityClass ** scP, int *siP)
155 {                               /* security class index */
156     LOCK_GLOBAL_MUTEX;
157     *scP = 0;
158     switch (service) {
159     case KA_AUTHENTICATION_SERVICE:
160     case KA_TICKET_GRANTING_SERVICE:
161       no_security:
162         *scP = rxnull_NewClientSecurityObject();
163         *siP = RX_SCINDEX_NULL;
164         break;
165     case KA_MAINTENANCE_SERVICE:
166         if (!token)
167             goto no_security;
168         *scP =
169             rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
170                                           token->kvno, token->ticketLen,
171                                           token->ticket);
172         *siP = RX_SCINDEX_KAD;
173         break;
174     default:
175         UNLOCK_GLOBAL_MUTEX;
176         return KABADARGUMENT;
177     }
178     if (*scP == 0) {
179         printf("Failed gettting security object\n");
180         UNLOCK_GLOBAL_MUTEX;
181         return KARXFAIL;
182     }
183     UNLOCK_GLOBAL_MUTEX;
184     return 0;
185 }
186
187 afs_int32
188 ka_SingleServerConn(char *cell, char *server,   /* name of server to contact */
189                     int service, struct ktc_token * token,
190                     struct ubik_client ** conn)
191 {
192     afs_int32 code;
193     struct rx_connection *serverconns[2];
194     struct rx_securityClass *sc;
195     int si;                     /* security class index */
196     struct afsconf_cell cellinfo;       /* for cell auth server list */
197     int i;
198     int match;
199     char sname[MAXHOSTCHARS];
200     int snamel;
201
202     LOCK_GLOBAL_MUTEX;
203     code = ka_GetServers(cell, &cellinfo);
204     if (code) {
205         UNLOCK_GLOBAL_MUTEX;
206         return code;
207     }
208
209     lcstring(sname, server, sizeof(sname));
210     snamel = strlen(sname);
211     match = -1;
212     for (i = 0; i < cellinfo.numServers; i++) {
213         if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
214             if (match >= 0) {
215                 UNLOCK_GLOBAL_MUTEX;
216                 return KANOCELLS;
217             } else
218                 match = i;
219         }
220     }
221     if (match < 0) {
222         UNLOCK_GLOBAL_MUTEX;
223         return KANOCELLS;
224     }
225
226     code = rx_Init(0);
227     if (code) {
228         UNLOCK_GLOBAL_MUTEX;
229         return code;
230     }
231
232     code = ka_GetSecurity(service, token, &sc, &si);
233     if (code) {
234         UNLOCK_GLOBAL_MUTEX;
235         return code;
236     }
237 #ifdef AFS_PTHREAD_ENV
238     serverconns[0] =
239         rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
240                                cellinfo.hostAddr[match].sin_port, service, sc,
241                                si);
242 #else
243     serverconns[0] =
244         rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
245                          cellinfo.hostAddr[match].sin_port, service, sc, si);
246 #endif
247     serverconns[1] = 0;         /* terminate list */
248
249     /* next, pass list of server rx_connections (in serverconns), and a place
250      * to put the returned client structure that we'll use in all of our rpc
251      * calls (via ubik_Call) */
252     *conn = 0;
253     code = ubik_ClientInit(serverconns, conn);
254     rxs_Release(sc);
255     UNLOCK_GLOBAL_MUTEX;
256     if (code)
257         return KAUBIKINIT;
258     return 0;
259 }
260
261 afs_int32
262 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
263                            struct afsconf_cell * cellinfo,
264                            struct ubik_client ** conn)
265 {
266     afs_int32 code;
267     struct rx_connection *serverconns[MAXSERVERS];
268     struct rx_securityClass *sc;
269     int si;                     /* security class index */
270     int i;
271
272     LOCK_GLOBAL_MUTEX;
273     code = rx_Init(0);
274     if (code) {
275         UNLOCK_GLOBAL_MUTEX;
276         return code;
277     }
278
279     code = ka_GetSecurity(service, token, &sc, &si);
280     if (code) {
281         UNLOCK_GLOBAL_MUTEX;
282         return code;
283     }
284
285     for (i = 0; i < cellinfo->numServers; i++)
286 #ifdef AFS_PTHREAD_ENV
287         serverconns[i] =
288             rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
289                                    cellinfo->hostAddr[i].sin_port, service,
290                                    sc, si);
291 #else
292         serverconns[i] =
293             rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
294                              cellinfo->hostAddr[i].sin_port, service, sc, si);
295 #endif
296     serverconns[cellinfo->numServers] = 0;      /* terminate list */
297
298     /* next, pass list of server rx_connections (in serverconns), and a place
299      * to put the returned client structure that we'll use in all of our rpc
300      * calls (via ubik_Call) */
301     *conn = 0;
302     code = ubik_ClientInit(serverconns, conn);
303     rxs_Release(sc);
304     UNLOCK_GLOBAL_MUTEX;
305     if (code)
306         return KAUBIKINIT;
307     return 0;
308 }
309
310 afs_int32
311 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
312                   struct ubik_client ** conn)
313 {
314     afs_int32 code;
315     struct rx_connection *serverconns[MAXSERVERS];
316     struct rx_securityClass *sc;
317     int si;                     /* security class index */
318     int i;
319     struct afsconf_cell cellinfo;       /* for cell auth server list */
320
321     LOCK_GLOBAL_MUTEX;
322     code = ka_GetServers(cell, &cellinfo);
323     if (code) {
324         UNLOCK_GLOBAL_MUTEX;
325         return code;
326     }
327
328     code = rx_Init(0);
329     if (code) {
330         UNLOCK_GLOBAL_MUTEX;
331         return code;
332     }
333
334     code = ka_GetSecurity(service, token, &sc, &si);
335     if (code) {
336         UNLOCK_GLOBAL_MUTEX;
337         return code;
338     }
339
340     for (i = 0; i < cellinfo.numServers; i++)
341 #ifdef AFS_PTHREAD_ENV
342         serverconns[i] =
343             rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
344                                    cellinfo.hostAddr[i].sin_port, service, sc,
345                                    si);
346 #else
347         serverconns[i] =
348             rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
349                              cellinfo.hostAddr[i].sin_port, service, sc, si);
350 #endif
351     serverconns[cellinfo.numServers] = 0;       /* terminate list */
352
353     /* next, pass list of server rx_connections (in serverconns), and a place
354      * to put the returned client structure that we'll use in all of our rpc
355      * calls (via ubik_Call) */
356     *conn = 0;
357     code = ubik_ClientInit(serverconns, conn);
358     rxs_Release(sc);
359     UNLOCK_GLOBAL_MUTEX;
360     if (code)
361         return KAUBIKINIT;
362     return 0;
363 }
364
365 static afs_int32
366 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
367                   struct ktc_token *token, struct ktc_principal *caller,
368                   struct ktc_principal *server, char *label,
369                   afs_int32 * pwexpires)
370 {
371     struct ka_ticketAnswer *answer;
372     afs_uint32 cksum;
373     unsigned char tempc;
374
375     answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
376
377     cksum = ntohl(answer->cksum);
378     if (challenge != ntohl(answer->challenge))
379         return KABADPROTOCOL;
380     memcpy(&token->sessionKey, &answer->sessionKey,
381            sizeof(token->sessionKey));
382     token->startTime = ntohl(answer->startTime);
383     token->endTime = ntohl(answer->endTime);
384     token->kvno = (short)ntohl(answer->kvno);
385     token->ticketLen = ntohl(answer->ticketLen);
386
387     if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
388         return KABADPROTOCOL;
389     if ((token->ticketLen < MINKTCTICKETLEN)
390         || (token->ticketLen > MAXKTCTICKETLEN))
391         return KABADPROTOCOL;
392
393     {
394         char *strings = answer->name;
395         int len;
396 #undef chkstr
397 #define chkstr(field) \
398         len = strlen (strings); \
399         if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
400         if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
401         strings += len+1
402
403         if (caller) {
404             chkstr(caller->name);
405             chkstr(caller->instance);
406             chkstr(caller->cell);
407         } else {
408             chkstr(0);
409             chkstr(0);
410             chkstr(0);
411         }
412         if (server) {
413             chkstr(server->name);
414             chkstr(server->instance);
415         } else {
416             chkstr(0);
417             chkstr(0);
418         }
419
420         if (oanswer->SeqLen -
421             ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
422             >= (ENCRYPTIONBLOCKSIZE + 12)
423             )
424             return KABADPROTOCOL;
425
426         memcpy(token->ticket, strings, token->ticketLen);
427         strings += token->ticketLen;
428         if (memcmp(strings, label, KA_LABELSIZE) != 0)
429             return KABADPROTOCOL;
430
431         if (pwexpires) {
432             afs_int32 temp;
433             strings += KA_LABELSIZE;
434             temp = round_up_to_ebs((strings - oanswer->SeqBody));
435
436             if (oanswer->SeqLen > temp) {
437                 strings = oanswer->SeqBody + temp;
438                 memcpy(&temp, strings, sizeof(afs_int32));
439                 tempc = ntohl(temp) >> 24;
440                 /* don't forget this if you add any more fields!
441                  * strings += sizeof(afs_int32);
442                  */
443             } else {
444                 tempc = 255;
445             }
446             *pwexpires = tempc;
447         }
448
449     }
450     return 0;
451 }
452
453 /* call this instead of stub and we'll guarantee to find a host that's up.
454  * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
455  */
456 static afs_int32
457 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
458      struct ubik_client *aclient;
459      int (*aproc) ();
460      afs_int32 aflags;
461      void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
462 {
463     afs_int32 code, lcode;
464     int count;
465     int pass;
466
467     /* First pass only checks servers known running. Second checks all.
468      * Once we've cycled through all the servers and still nothing, return
469      * error code from the last server tried.
470      */
471     for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
472          pass++, aflags &= ~UPUBIKONLY) {
473         code = 0;
474         count = 0;
475         do {                    /* Cycle through the servers */
476             lcode = code;
477             code =
478                 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
479                               (long) p2, (long) p3, (long) p4,
480                               (long) p5, (long) p6, (long) p7,
481                               (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
482         } while ((code == UNOQUORUM) || (code == UNOTSYNC)
483                  || (code == KALOCKED) || (code == -1));
484
485         if (code != UNOSERVERS)
486             break;
487     }
488
489     /* If cycled through all the servers, return the last error code */
490     if ((code == UNOSERVERS) && lcode) {
491         code = lcode;
492     }
493     return code;
494 }
495
496 /* This is the interface to the AuthServer RPC routine Authenticate.  It
497    formats the request packet, calls the encryption routine on the answer,
498    calls Authenticate, and decrypts the response.  The response is checked for
499    correctness and its contents are copied into the token. */
500
501 /* Errors:
502      KABADKEY = the key failed when converted to a key schedule.  Probably bad
503        parity.
504      KAUBIKCALL - the call to Ubik returned an error, probably a communication
505        failure such as timeout.
506      KABADPROTOCOL - the returned packet was in error.  Since a packet was
507        returned it can be presumed that the AuthServer correctly interpreted
508        the response.  This may indicate an inauthentic AuthServer.
509      <other> - errors generated by the server process are returned directly.
510  */
511
512 afs_int32
513 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn,      /* Ubik connection to the AuthServer in
514                                                                                          * the desired cell */
515                 int service,    /* ticket granting or admin service */
516                 struct ktc_encryptionKey * key, Date start, Date end,   /* ticket lifetime */
517                 struct ktc_token * token, afs_int32 * pwexpires)
518 {                               /* days until it expires */
519     afs_int32 code;
520     des_key_schedule schedule;
521     Date request_time;
522     struct ka_gettgtRequest request;
523     struct ka_gettgtAnswer answer_old;
524     struct ka_ticketAnswer answer;
525     ka_CBS arequest;
526     ka_BBS oanswer;
527     char *req_label;
528     char *ans_label;
529     int version;
530
531     LOCK_GLOBAL_MUTEX;
532     if ((code = des_key_sched(key, schedule))) {
533         UNLOCK_GLOBAL_MUTEX;
534         return KABADKEY;
535     }
536
537     if (service == KA_MAINTENANCE_SERVICE) {
538         req_label = KA_GETADM_REQ_LABEL;
539         ans_label = KA_GETADM_ANS_LABEL;
540     } else if (service == KA_TICKET_GRANTING_SERVICE) {
541         req_label = KA_GETTGT_REQ_LABEL;
542         ans_label = KA_GETTGT_ANS_LABEL;
543     } else {
544         UNLOCK_GLOBAL_MUTEX;
545         return KABADARGUMENT;
546     }
547
548     request_time = time(0);
549     request.time = htonl(request_time);
550     memcpy(request.label, req_label, sizeof(request.label));
551     arequest.SeqLen = sizeof(request);
552     arequest.SeqBody = (char *)&request;
553     des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
554                      schedule, key, ENCRYPT);
555
556     oanswer.MaxSeqLen = sizeof(answer);
557     oanswer.SeqLen = 0;
558     oanswer.SeqBody = (char *)&answer;
559
560     version = 2;
561     code =
562         kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, start,
563                          end, &arequest, &oanswer);
564     if (code == RXGEN_OPCODE) {
565         oanswer.MaxSeqLen = sizeof(answer);
566         oanswer.SeqBody = (char *)&answer;
567         version = 1;
568         code =
569             ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
570                       &arequest, &oanswer);
571         if (code == RXGEN_OPCODE) {
572             extern int KAA_Authenticate_old();
573             oanswer.MaxSeqLen = sizeof(answer_old);
574             oanswer.SeqBody = (char *)&answer_old;
575             version = 0;
576             code =
577                 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
578                           start, end, &arequest, &oanswer);
579         }
580         if (code == RXGEN_OPCODE) {
581             code = KAOLDINTERFACE;
582         }
583     }
584     if (code) {
585         UNLOCK_GLOBAL_MUTEX;
586         if ((code >= KAMINERROR) && (code <= KAMAXERROR))
587             return code;
588         return KAUBIKCALL;
589     }
590     des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
591                      schedule, key, DECRYPT);
592
593     switch (version) {
594     case 1:
595     case 2:
596         {
597             struct ktc_principal caller;
598             strcpy(caller.name, name);
599             strcpy(caller.instance, instance);
600             strcpy(caller.cell, "");
601             code =
602                 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
603                                   0, ans_label, pwexpires);
604             if (code) {
605                 UNLOCK_GLOBAL_MUTEX;
606                 return code;
607             }
608         }
609         break;
610     case 0:
611         answer_old.time = ntohl(answer_old.time);
612         answer_old.ticket_len = ntohl(answer_old.ticket_len);
613         if ((answer_old.time != request_time + 1)
614             || (answer_old.ticket_len < MINKTCTICKETLEN)
615             || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
616             UNLOCK_GLOBAL_MUTEX;
617             return KABADPROTOCOL;
618         }
619         {
620             char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
621
622             if (strncmp(label, ans_label, sizeof(answer_old.label))) {
623                 UNLOCK_GLOBAL_MUTEX;
624                 return KABADPROTOCOL;
625             }
626             token->startTime = start;
627             token->endTime = end;
628             token->kvno = ntohl(answer_old.kvno);
629             token->ticketLen = answer_old.ticket_len;
630             memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
631             memcpy(&token->sessionKey, &answer_old.sessionkey,
632                    sizeof(struct ktc_encryptionKey));
633         }
634         break;
635     default:
636         UNLOCK_GLOBAL_MUTEX;
637         return KAINTERNALERROR;
638     }
639
640     UNLOCK_GLOBAL_MUTEX;
641     return 0;
642 }
643
644 afs_int32
645 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn,        /* Ubik conn to cell's AuthServer */
646             Date start, Date end,       /* desired ticket lifetime */
647             struct ktc_token * auth_token, char *auth_domain,
648             struct ktc_token * token)
649 {
650     struct ka_getTicketTimes times;
651     struct ka_getTicketAnswer answer_old;
652     struct ka_ticketAnswer answer;
653     afs_int32 code;
654     ka_CBS aticket;
655     ka_CBS atimes;
656     ka_BBS oanswer;
657     char *strings;
658     int len;
659     des_key_schedule schedule;
660     int version;
661     afs_int32 pwexpires;
662
663     LOCK_GLOBAL_MUTEX;
664     aticket.SeqLen = auth_token->ticketLen;
665     aticket.SeqBody = auth_token->ticket;
666
667     code = des_key_sched(&auth_token->sessionKey, schedule);
668     if (code) {
669         UNLOCK_GLOBAL_MUTEX;
670         return KABADKEY;
671     }
672
673     times.start = htonl(start);
674     times.end = htonl(end);
675     des_ecb_encrypt(&times, &times, schedule, ENCRYPT);
676
677     atimes.SeqLen = sizeof(times);
678     atimes.SeqBody = (char *)&times;
679
680     oanswer.SeqLen = 0;
681     oanswer.MaxSeqLen = sizeof(answer);
682     oanswer.SeqBody = (char *)&answer;
683
684     version = 1;
685     code =
686         ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
687                   &aticket, name, instance, &atimes, &oanswer);
688     if (code == RXGEN_OPCODE) {
689         extern int KAT_GetTicket_old();
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, &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 }