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