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