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