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