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