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