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