2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
17 #ifdef HAVE_SYS_RESOURCE_H
18 # include <sys/resource.h>
21 #ifdef IGNORE_SOME_GCC_WARNINGS
22 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
28 #include <hcrypto/des.h>
36 #include <rx/rxkad_convert.h>
37 #include <afs/cellconfig.h>
39 #include <afs/com_err.h>
40 #include <afs/afsutil.h>
41 #include <afs/audit.h>
47 #include "kauth_internal.h"
49 #include "kadatabase.h"
52 extern struct ubik_dbase
*KA_dbase
;
53 struct kaheader cheader
;
54 Date cheaderReadTime
; /* time cheader last read in */
55 extern struct afsconf_dir
*KA_conf
; /* for getting cell info */
59 char lrealm
[MAXKTCREALMLEN
];
61 #ifndef EXPIREPW /* password expiration default yes */
65 #ifndef AUTOCPWINTERVAL
66 #define AUTOCPWINTERVAL (24*3600)
68 #ifndef AUTOCPWUPDATES
69 #define AUTOCPWUPDATES 128
74 static afs_int32 autoCPWInterval
;
75 static afs_int32 autoCPWUpdates
;
77 static afs_int32
set_password(struct ubik_trans
*tt
, char *name
,
79 struct ktc_encryptionKey
*password
,
80 afs_int32 kvno
, afs_int32 caller
);
81 static afs_int32
impose_reuse_limits(EncryptionKey
*password
,
82 struct kaentry
*tentry
);
83 static int create_user(struct ubik_trans
*tt
, char *name
, char *instance
,
84 struct ktc_encryptionKey
*key
, afs_int32 caller
,
87 /* This routine is called whenever an RPC interface needs the time. It uses
88 the current time to randomize a 128 bit value that is used to change the
89 AuthServer Admin and TGS keys automatically. */
91 static Date nextAutoCPWTime
= 0;
92 static afs_int32 totalUpdates
= 0;
94 /* This routine is ostensibly to get the current time, but basically its job is
95 to periodically update a random number. It also periodically updates the
96 keys for the builtin servers. This is why it needs a transaction pointer
97 and returns an error code. If the caller is in a read transaction, the tt
98 ptr should be zero and the return code need not be checked. */
101 get_time(Date
*timeP
,
102 struct ubik_trans
*tt
, /* tt != 0: a write transaction */
103 int admin
) /* the caller is an admin user */
105 /* random value used to change Admin & TGS keys, this is at risk during
106 * multi-threaded operation, but I think the consequences are fairly
108 static afs_uint32 random_value
[4];
111 unsigned int bit
, nbit
;
115 gettimeofday(&time
, NULL
);
116 bit
= (random_value
[3] >> 31) & 1; /* get high bit of high word */
117 for (i
= 0; i
< 4; i
++) {
118 nbit
= random_value
[i
] >> 31;
119 random_value
[i
] = (random_value
[i
] << 1) + bit
;
122 /* get 60ths from usec. This is all the real randomness there is. */
123 random_value
[0] += time
.tv_usec
/ 16667;
125 if (nextAutoCPWTime
== 0) { /* initialize things */
126 nextAutoCPWTime
= time
.tv_sec
+ autoCPWInterval
;
127 memcpy(&random_value
[0], &time
, 8);
128 memcpy(&random_value
[2], &time
, 8);
131 if ((++totalUpdates
>= autoCPWUpdates
) && tt
&& /* a write transaction */
132 ((admin
&& (time
.tv_sec
>= nextAutoCPWTime
))
133 || (time
.tv_sec
>= nextAutoCPWTime
+ autoCPWInterval
))) {
134 struct ktc_encryptionKey key
;
135 char buf
[4 * sizeof(key
) + 1];
136 struct kaentry tentry
;
138 char bob
[KA_TIMESTR_LEN
];
140 ka_timestr(time
.tv_sec
, bob
, KA_TIMESTR_LEN
);
141 es_Report("Auto CPW at %s\n", bob
);
143 es_Report(" ... even though no ADMIN user\n");
145 code
= FindBlock(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &to
, &tentry
);
148 if (to
) { /* check if auto cpw is disabled */
149 if (!(ntohl(tentry
.flags
) & KAFNOCPW
)) {
150 memcpy(&key
, &random_value
[0], sizeof(key
));
151 DES_set_odd_parity(ktc_to_cblock(&key
));
153 set_password(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &key
, 0,
156 DES_init_random_number_generator(ktc_to_cblock(&key
));
157 ka_ConvertBytes(buf
, sizeof(buf
), (char *)&key
,
159 es_Report("New Admin key is %s\n", buf
);
162 ("in get_time: set_password failed because: %d\n",
169 code
= FindBlock(tt
, KA_TGS_NAME
, lrealm
, &to
, &tentry
);
172 if (to
) { /* check if auto cpw is disabled */
173 if (!(ntohl(tentry
.flags
) & KAFNOCPW
)) {
174 memcpy(&key
, &random_value
[2], sizeof(key
));
175 DES_set_odd_parity(ktc_to_cblock(&key
));
176 code
= set_password(tt
, KA_TGS_NAME
, lrealm
, &key
, 0, 0);
178 ka_ConvertBytes(buf
, sizeof(buf
), (char *)&key
,
180 es_Report("New TGS key is %s\n", buf
);
183 ("in get_time: set_password failed because: %s\n",
184 afs_error_message(code
));
189 code
= ka_FillKeyCache(tt
); /* ensure in-core copy is uptodate */
193 nextAutoCPWTime
= time
.tv_sec
+ autoCPWInterval
;
197 *timeP
= time
.tv_sec
;
201 static int noAuthenticationRequired
; /* global state */
202 static int recheckNoAuth
; /* global state */
204 /* kaprocsInited is sort of a lock: during a transaction only one process runs
205 while kaprocsInited is false. */
207 static int kaprocsInited
= 0;
209 /* This variable is protected by the kaprocsInited flag. */
211 static int (*rebuildDatabase
) (struct ubik_trans
*);
213 /* This is called to initialize the database */
216 initialize_database(struct ubik_trans
*tt
)
218 struct ktc_encryptionKey key
;
221 gettimeofday((struct timeval
*)&key
, NULL
); /* this is just a cheap seed key */
222 DES_set_odd_parity(ktc_to_cblock(&key
));
223 DES_init_random_number_generator(ktc_to_cblock(&key
));
224 if ((code
= DES_new_random_key(ktc_to_cblock(&key
)))
226 create_user(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &key
, 0,
227 KAFNORMAL
| KAFNOSEAL
| KAFNOTGS
)))
229 if ((code
= DES_new_random_key(ktc_to_cblock(&key
)))
231 create_user(tt
, KA_TGS_NAME
, lrealm
, &key
, 0,
232 KAFNORMAL
| KAFNOSEAL
| KAFNOTGS
)))
237 /* This routine handles initialization required by this module. The initFlags
238 parameter passes some information about the command line arguments. */
241 init_kaprocs(const char *lclpath
, int initFlags
)
244 struct ubik_trans
*tt
;
245 struct ktc_encryptionKey key
;
250 return KAINTERNALERROR
;
252 return KAINTERNALERROR
;
253 code
= afsconf_GetLocalCell(KA_conf
, lrealm
, sizeof(lrealm
));
255 printf("** Can't determine local cell name!\n");
258 ucstring(lrealm
, lrealm
, sizeof(lrealm
));
262 noAuthenticationRequired
= 1;
266 noAuthenticationRequired
= afsconf_GetNoAuthFlag(KA_conf
);
267 if (noAuthenticationRequired
)
268 printf("Running server with security disabled\n");
271 autoCPWInterval
= 10;
274 autoCPWInterval
= AUTOCPWINTERVAL
;
275 autoCPWUpdates
= AUTOCPWUPDATES
;
278 init_kadatabase(initFlags
);
279 rebuildDatabase
= initialize_database
;
281 if ((code
= InitAuthServ(&tt
, LOCKREAD
, 0))) {
282 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code
);
285 code
= ka_LookupKey(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &kvno
, &key
);
289 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
293 DES_init_random_number_generator(ktc_to_cblock(&key
));
295 code
= ubik_EndTrans(tt
);
297 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code
);
301 kaux_opendb((char *)lclpath
);/* aux database stores failure counters */
302 rebuildDatabase
= 0; /* only do this during init */
307 /* These variable are for returning debugging info about the state of the
308 server. If they get trashed during multi-threaded operation it doesn't
311 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
312 char *lastOperation
= 0; /* name of last operation */
313 static Date lastTrans
; /* time of last transaction */
315 static char adminPrincipal
[256];
316 static char authPrincipal
[256];
317 static char tgsPrincipal
[256];
318 static char tgsServerPrincipal
[256];
321 save_principal(char *p
, char *n
, char *i
, char *c
)
331 if (i
&& strlen(i
)) {
341 if (c
&& strlen(c
)) {
353 check_auth(struct rx_call
*call
,
354 struct ubik_trans
*at
,
355 int admin
, /* require caller to be ADMIN */
356 afs_int32
*acaller_id
)
359 char name
[MAXKTCNAMELEN
];
360 char instance
[MAXKTCNAMELEN
];
361 char cell
[MAXKTCREALMLEN
];
363 Date expiration
; /* checked by Security Module */
364 struct kaentry tentry
;
371 noAuthenticationRequired
= afsconf_GetNoAuthFlag(KA_conf
);
373 si
= rx_SecurityClassOf(rx_ConnectionOf(call
));
374 if (si
== RX_SECIDX_VAB
) {
375 printf("No support for VAB security module yet.\n");
377 } else if (si
== RX_SECIDX_NULL
) {
380 } else if (si
!= RX_SECIDX_KAD
) {
381 es_Report("Unknown security index %d\n", si
);
386 rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, &expiration
, name
,
387 instance
, cell
, &kvno
);
391 if (level
!= rxkad_crypt
) {
392 es_Report("Incorrect security level = %d\n", level
);
397 if (!name_instance_legal(name
, instance
))
401 ("Authorization rejected because we don't understand intercell stuff yet: ",
403 printf("@%s\n", cell
);
407 code
= FindBlock(at
, name
, instance
, acaller_id
, &tentry
);
410 if (*acaller_id
== 0) {
411 ka_PrintUserID("User ", name
, instance
, " unknown.\n");
414 save_principal(adminPrincipal
, name
, instance
, 0);
417 if (!(ntohl(tentry
.flags
) & KAFADMIN
)) {
418 if (noAuthenticationRequired
) {
419 ka_PrintUserID("Authorization approved for ", name
, instance
,
420 " because there is no authentication required\n");
421 osi_auditU(call
, UnAuthEvent
, code
, AUD_STR
, name
, AUD_STR
,
422 instance
, AUD_STR
, cell
, AUD_END
);
425 ka_PrintUserID("User ", name
, instance
, " is not ADMIN.\n");
428 osi_auditU(call
, UseOfPrivilegeEvent
, code
, AUD_STR
, name
, AUD_STR
,
429 instance
, AUD_STR
, cell
, AUD_END
);
434 if (noAuthenticationRequired
) {
436 ("Caller w/o authorization approved no authentication required\n");
437 osi_auditU(call
, UnAuthEvent
, code
, AUD_STR
, name
, AUD_STR
, instance
,
438 AUD_STR
, cell
, AUD_END
);
441 return code
; /* no auth info */
445 AwaitInitialization(void)
448 while (!kaprocsInited
) {
451 else if (time(0) - start
> 5)
458 /* This is called by every RPC interface to create a Ubik transaction and read
459 the database header into core */
462 InitAuthServ(struct ubik_trans
**tt
,
463 int lock
, /* indicate read/write transaction */
464 int *this_op
) /* opcode of RPC proc, for COUNT_ABO */
467 afs_int32 start
= 0; /* time started waiting for quorum */
468 float wait
= 0.91; /* start waiting for 1 second */
470 /* Wait for server initialization to finish if not during init_kaprocs */
472 if ((code
= AwaitInitialization()))
475 for (code
= UNOQUORUM
; code
== UNOQUORUM
;) {
476 if (lock
== LOCKREAD
)
477 code
= ubik_BeginTransReadAny(KA_dbase
, UBIK_READTRANS
, tt
);
479 code
= ubik_BeginTrans(KA_dbase
, UBIK_WRITETRANS
, tt
);
480 if (code
== UNOQUORUM
) { /* no quorum elected */
484 int delay
= time(0) - start
;
485 if (this_op
) { /* punt quickly, if RPC call */
488 } else { /* more patient during init. */
493 printf("Waiting for quorum election.\n");
496 IOMGR_Sleep((int)wait
);
501 if ((code
= ubik_SetLock(*tt
, 1, 1, lock
))) {
504 ubik_AbortTrans(*tt
);
507 /* check that dbase is initialized and setup cheader */
508 if (lock
== LOCKREAD
) {
509 /* init but don't fix because this is read only */
510 code
= CheckInit(*tt
, 0);
512 ubik_AbortTrans(*tt
); /* abort, since probably I/O error */
513 /* we did the check under a ReadAny transaction, but now, after
514 * getting a write transaction (and thus some real guarantees
515 * about what databases are really out there), we will check again
516 * in CheckInit before nuking the database. Since this may now get
517 * a UNOQUORUM we'll just do this from the top.
519 if ((code
= InitAuthServ(tt
, LOCKWRITE
, this_op
)))
521 if ((code
= ubik_EndTrans(*tt
)))
524 /* now open the read transaction that was originally requested. */
525 return InitAuthServ(tt
, lock
, this_op
);
528 if ((code
= CheckInit(*tt
, rebuildDatabase
))) {
531 ubik_AbortTrans(*tt
);
536 ka_FillKeyCache(*tt
); /* ensure in-core copy is uptodate */
540 /* returns true if name is specially known by AuthServer */
543 special_name(char *name
, char *instance
)
546 return ((!strcmp(name
, KA_TGS_NAME
) && !strcmp(instance
, lrealm
))
547 || (strcmp(name
, KA_ADMIN_NAME
) == 0));
551 create_user(struct ubik_trans
*tt
, char *name
, char *instance
,
552 struct ktc_encryptionKey
*key
, afs_int32 caller
,
557 struct kaentry tentry
;
558 afs_int32 maxLifetime
;
560 code
= FindBlock(tt
, name
, instance
, &to
, &tentry
);
564 return KAEXIST
; /* name already exists, we fail */
566 to
= AllocBlock(tt
, &tentry
);
570 /* otherwise we have a block */
571 strncpy(tentry
.userID
.name
, name
, sizeof(tentry
.userID
.name
));
572 strncpy(tentry
.userID
.instance
, instance
, sizeof(tentry
.userID
.instance
));
573 tentry
.flags
= htonl(flags
);
574 if (special_name(name
, instance
)) { /* this overrides key & version */
575 tentry
.flags
= htonl(ntohl(tentry
.flags
) | KAFSPECIAL
);
576 tentry
.key_version
= htonl(-1); /* don't save this key */
577 if ((code
= ka_NewKey(tt
, to
, &tentry
, key
)))
580 memcpy(&tentry
.key
, key
, sizeof(tentry
.key
));
581 tentry
.key_version
= htonl(0);
583 tentry
.user_expiration
= htonl(NEVERDATE
);
584 code
= get_time(&tentry
.modification_time
, tt
, 1);
588 /* time and addr of entry for guy changing this entry */
589 tentry
.modification_time
= htonl(tentry
.modification_time
);
590 tentry
.modification_id
= htonl(caller
);
591 tentry
.change_password_time
= tentry
.modification_time
;
593 if (strcmp(name
, KA_TGS_NAME
) == 0)
594 maxLifetime
= MAXKTCTICKETLIFETIME
;
595 else if (strcmp(name
, KA_ADMIN_NAME
) == 0)
596 maxLifetime
= 10 * 3600;
597 else if (strcmp(name
, AUTH_SUPERUSER
) == 0)
598 maxLifetime
= 100 * 3600;
600 maxLifetime
= 25 * 3600; /* regular users */
601 tentry
.max_ticket_lifetime
= htonl(maxLifetime
);
603 code
= ThreadBlock(tt
, to
, &tentry
);
607 /* Put actual stub routines here */
610 SKAM_CreateUser(struct rx_call
*call
, char *aname
, char *ainstance
,
611 EncryptionKey ainitpw
)
615 code
= kamCreateUser(call
, aname
, ainstance
, ainitpw
);
616 osi_auditU(call
, AFS_KAM_CrUserEvent
, code
, AUD_STR
, aname
, AUD_STR
,
623 kamCreateUser(struct rx_call
*call
, char *aname
, char *ainstance
,
624 EncryptionKey ainitpw
)
627 struct ubik_trans
*tt
;
628 afs_int32 caller
; /* Disk offset of caller's entry */
630 COUNT_REQ(CreateUser
);
631 if (!DES_check_key_parity(EncryptionKey_to_cblock(&ainitpw
)) ||
632 DES_is_weak_key(EncryptionKey_to_cblock(&ainitpw
)))
634 if (!name_instance_legal(aname
, ainstance
))
636 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
638 code
= check_auth(call
, tt
, 1, &caller
);
644 code
= create_user(tt
, aname
, ainstance
, EncryptionKey_to_ktc(&ainitpw
), caller
, KAFNORMAL
);
650 code
= ubik_EndTrans(tt
);
651 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
,
652 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_CRUSER
);
657 SKAA_ChangePassword(struct rx_call
*call
, char *aname
, char *ainstance
,
658 ka_CBS
*arequest
, ka_BBS
*oanswer
)
662 code
= ChangePassWord(call
, aname
, ainstance
, arequest
, oanswer
);
663 osi_auditU(call
, AFS_KAA_ChPswdEvent
, code
, AUD_STR
, aname
, AUD_STR
,
669 ChangePassWord(struct rx_call
*call
, char *aname
, char *ainstance
,
670 ka_CBS
*arequest
, ka_BBS
*oanswer
)
673 struct ubik_trans
*tt
;
674 afs_int32 to
; /* offset of block */
675 struct kaentry tentry
;
676 struct ka_cpwRequest request
; /* request after decryption */
677 char *answer
; /* where answer is to be put */
678 int answer_len
; /* length of answer packet */
679 afs_int32 kvno
; /* requested key version number */
680 DES_key_schedule user_schedule
; /* key schedule for user's key */
681 Date request_time
; /* time request originated */
683 COUNT_REQ(ChangePassword
);
684 if (!name_instance_legal(aname
, ainstance
))
686 if (strcmp(ainstance
, KA_ADMIN_NAME
) == 0)
688 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
691 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
695 if (to
== 0) { /* no such user */
699 if (ntohl(tentry
.flags
) & KAFNOCPW
) {
704 /* decrypt request w/ user password */
705 if ((code
= DES_key_sched(ktc_to_cblock(&tentry
.key
), &user_schedule
)))
706 es_Report("In KAChangePassword: key_sched returned %d\n", code
);
707 DES_pcbc_encrypt(arequest
->SeqBody
, &request
,
708 min(arequest
->SeqLen
, sizeof(request
)), &user_schedule
,
709 ktc_to_cblockptr(&tentry
.key
), DECRYPT
);
711 /* validate the request */
712 request_time
= ntohl(request
.time
); /* reorder date */
713 kvno
= ntohl(request
.kvno
);
714 if (check_ka_skew(request_time
, time(NULL
), KTC_TIME_UNCERTAINTY
) ||
715 strncmp(request
.label
, KA_CPW_REQ_LABEL
, sizeof(request
.label
)) ||
716 request
.spare
|| kvno
> MAXKAKVNO
) { /* these are reserved */
721 /* check to see if the new password was used before, or if there has
722 * not been sufficient time since the last password change
724 code
= impose_reuse_limits(ktc_to_EncryptionKey(&request
.newpw
), &tentry
);
729 /* Create the Answer Packet */
730 answer_len
= sizeof(Date
) + KA_LABELSIZE
;
731 if (oanswer
->MaxSeqLen
< answer_len
) {
732 code
= KAANSWERTOOLONG
;
735 oanswer
->SeqLen
= answer_len
;
736 answer
= oanswer
->SeqBody
;
737 request
.time
= htonl(request_time
+ 1);
738 memcpy(answer
, (char *)&request
.time
, sizeof(Date
));
739 answer
+= sizeof(Date
);
740 memcpy(answer
, KA_CPW_ANS_LABEL
, KA_LABELSIZE
);
742 DES_pcbc_encrypt(oanswer
->SeqBody
, oanswer
->SeqBody
, answer_len
,
743 &user_schedule
, ktc_to_cblockptr(&tentry
.key
), ENCRYPT
);
745 code
= set_password(tt
, aname
, ainstance
, &request
.newpw
, kvno
, 0);
751 cheader
.stats
.cpws
= htonl(ntohl(cheader
.stats
.cpws
) + 1);
753 kawrite(tt
, DOFFSET(0, &cheader
, &cheader
.stats
.cpws
),
754 (char *)&cheader
.stats
.cpws
, sizeof(afs_int32
));
760 code
= ubik_EndTrans(tt
);
770 impose_reuse_limits(EncryptionKey
*password
, struct kaentry
*tentry
)
778 if (!tentry
->pwsums
[0] && npwSums
> 1 && !tentry
->pwsums
[1])
779 return 0; /* password reuse limits not in effect */
781 code
= get_time(&now
, 0, 0);
785 if ((now
- ntohl(tentry
->change_password_time
)) < MinHours
* 60 * 60)
788 if (!memcmp(password
, &(tentry
->key
), sizeof(EncryptionKey
)))
791 code
= ka_KeyCheckSum((char *)password
, &newsum
);
795 newsum
= newsum
& 0x000000ff;
796 for (i
= 0; i
< npwSums
; i
++) {
797 if (newsum
== tentry
->pwsums
[i
])
806 set_password(struct ubik_trans
*tt
, char *name
, char *instance
,
807 struct ktc_encryptionKey
*password
, afs_int32 kvno
, afs_int32 caller
)
810 afs_int32 to
; /* offset of block */
811 struct kaentry tentry
;
817 code
= FindBlock(tt
, name
, instance
, &to
, &tentry
);
821 return KANOENT
; /* no such user */
823 /* if password reuse limits in effect, set the checksums, the hard way */
824 if (!tentry
.pwsums
[0] && npwSums
> 1 && !tentry
.pwsums
[1]) {
825 /* do nothing, no limits */ ;
827 code
= ka_KeyCheckSum((char *)&(tentry
.key
), &newsum
);
830 for (i
= npwSums
- 1; i
; i
--)
831 tentry
.pwsums
[i
] = tentry
.pwsums
[i
- 1];
832 tentry
.pwsums
[0] = newsum
& 0x000000ff;
836 if (special_name(name
, instance
)) { /* set key over rides key_version */
837 tentry
.flags
= htonl(ntohl(tentry
.flags
) | KAFSPECIAL
);
838 if ((code
= ka_NewKey(tt
, to
, &tentry
, password
)))
841 memcpy(&tentry
.key
, password
, sizeof(tentry
.key
));
843 kvno
= ntohl(tentry
.key_version
);
844 if ((kvno
< 1) || (kvno
>= MAXKAKVNO
))
849 tentry
.key_version
= htonl((afs_int32
) kvno
); /* requested key version */
854 /* no-write prevents recursive call to set_password by AuthCPW code. */
855 code
= get_time(&now
, 0, 0);
859 tentry
.modification_time
= htonl(now
);
860 tentry
.modification_id
= htonl(caller
);
863 tentry
.change_password_time
= htonl(now
);
865 if ((code
= kawrite(tt
, to
, (char *) &tentry
, sizeof(tentry
))))
871 SKAM_SetPassword(struct rx_call
*call
, char *aname
, char *ainstance
,
872 afs_int32 akvno
, EncryptionKey apassword
)
876 code
= kamSetPassword(call
, aname
, ainstance
, akvno
, apassword
);
877 osi_auditU(call
, AFS_KAM_SetPswdEvent
, code
, AUD_STR
, aname
, AUD_STR
,
883 kamSetPassword(struct rx_call
*call
, char *aname
, char *ainstance
,
884 afs_int32 akvno
, EncryptionKey apassword
)
887 struct ubik_trans
*tt
;
888 afs_int32 caller
; /* Disk offset of caller's entry */
889 struct kaentry tentry
;
891 COUNT_REQ(SetPassword
);
892 if (akvno
> MAXKAKVNO
)
893 return KABADARGUMENT
;
894 if (!DES_check_key_parity(EncryptionKey_to_cblock(&apassword
)) ||
895 DES_is_weak_key(EncryptionKey_to_cblock(&apassword
)))
898 if (!name_instance_legal(aname
, ainstance
))
900 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
902 code
= check_auth(call
, tt
, 0, &caller
);
906 if ((code
= karead(tt
, caller
, (char *)&tentry
, sizeof(tentry
)))) {
910 /* if the user is changing his own password or ADMIN then go ahead. */
911 if ((strcmp(tentry
.userID
.name
, aname
) == 0)
912 && (strcmp(tentry
.userID
.instance
, ainstance
) == 0)) {
913 if (ntohl(tentry
.flags
) & KAFNOCPW
)
916 code
= impose_reuse_limits(&apassword
, &tentry
);
919 set_password(tt
, aname
, ainstance
, EncryptionKey_to_ktc(&apassword
), akvno
, 0);
921 } else if (ntohl(tentry
.flags
) & KAFADMIN
) {
922 code
= set_password(tt
, aname
, ainstance
, EncryptionKey_to_ktc(&apassword
), akvno
, caller
);
928 code
= ubik_EndTrans(tt
);
929 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
,
930 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_CHPASSWD
);
940 CoerseLifetime(Date start
, Date end
)
942 unsigned char kerberosV4Life
;
943 kerberosV4Life
= time_to_life(start
, end
);
944 end
= life_to_time(start
, kerberosV4Life
);
949 GetEndTime(Date start
, /* start time of ticket */
950 Date reqEnd
, /* requested end time */
951 Date expiration
, /* authorizing ticket's expiration */
952 struct kaentry
*caller
,
953 struct kaentry
*server
,
954 Date
*endP
) /* actual end time */
960 if (ntohl(caller
->flags
) & KAFNOTGS
)
961 return KABADUSER
; /* no new tickets for this user */
962 if (expiration
&& (ntohl(server
->flags
) & KAFNOSEAL
))
963 return KABADSERVER
; /* can't be target of GetTicket req */
965 expiration
= NEVERDATE
;
967 cExp
= ntohl(caller
->user_expiration
);
968 sExp
= ntohl(server
->user_expiration
);
973 cLife
= start
+ ntohl(caller
->max_ticket_lifetime
);
974 sLife
= start
+ ntohl(server
->max_ticket_lifetime
);
976 umin(umin(reqEnd
, expiration
),
977 umin(umin(cLife
, sLife
), umin(cExp
, sExp
)));
978 end
= CoerseLifetime(start
, end
);
984 PrepareTicketAnswer(ka_BBS
*oanswer
, afs_int32 challenge
, char *ticket
,
985 afs_int32 ticketLen
, struct ktc_encryptionKey
*sessionKey
,
986 Date start
, Date end
, struct kaentry
*caller
,
987 struct kaentry
*server
, char *cell
, char *label
)
990 struct ka_ticketAnswer
*answer
;
993 code
= KAANSWERTOOLONG
;
994 if (oanswer
->MaxSeqLen
<
995 sizeof(struct ka_ticketAnswer
) - 5 * MAXKTCNAMELEN
- MAXKTCTICKETLEN
+
999 answer
= (struct ka_ticketAnswer
*)oanswer
->SeqBody
;
1000 answer
->challenge
= htonl(challenge
);
1001 memcpy(&answer
->sessionKey
, sessionKey
, sizeof(struct ktc_encryptionKey
));
1002 answer
->startTime
= htonl(start
);
1003 answer
->endTime
= htonl(end
);
1004 answer
->kvno
= server
->key_version
;
1005 answer
->ticketLen
= htonl(ticketLen
);
1008 char *ans
= answer
->name
; /* pointer to variable part */
1009 int rem
; /* space remaining */
1010 int len
; /* macro temp. */
1012 rem
= oanswer
->MaxSeqLen
- (ans
- oanswer
->SeqBody
);
1014 #define putstr(str) len = strlen (str)+1;\
1015 if (rem < len) return code;\
1017 ans += len; rem -= len
1018 putstr(caller
->userID
.name
);
1019 putstr(caller
->userID
.instance
);
1021 putstr(server
->userID
.name
);
1022 putstr(server
->userID
.instance
);
1023 if (rem
< ticketLen
+ KA_LABELSIZE
)
1025 memcpy(ans
, ticket
, ticketLen
);
1028 memcpy(ans
, label
, KA_LABELSIZE
);
1030 memset(ans
, 0, KA_LABELSIZE
);
1031 ans
+= KA_LABELSIZE
;
1032 oanswer
->SeqLen
= (ans
- oanswer
->SeqBody
);
1035 answer
->cksum
= htonl(cksum
);
1036 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1037 if (oanswer
->SeqLen
> oanswer
->MaxSeqLen
)
1042 /* This is used to get a ticket granting ticket or an admininstration ticket.
1043 These two specific, built-in servers are special cases, which require the
1044 client's key as an additional security precaution. The GetTicket operation
1045 is normally disabled for these two principals. */
1048 Authenticate(int version
, struct rx_call
*call
, char *aname
, char *ainstance
,
1049 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1052 struct ubik_trans
*tt
;
1053 afs_int32 to
; /* offset of block */
1055 struct kaentry server
; /* entry for desired server */
1056 struct ka_gettgtRequest request
; /* request after decryption */
1057 int tgt
, adm
; /* type of request */
1058 char *sname
; /* principal of server */
1060 char ticket
[MAXKTCTICKETLEN
]; /* our copy of the ticket */
1062 struct ktc_encryptionKey sessionKey
; /* we have to invent a session key */
1063 char *answer
; /* where answer is to be put */
1064 int answer_len
; /* length of answer packet */
1065 Date answer_time
; /* 1+ request time in network order */
1066 afs_int32 temp
; /* for htonl conversions */
1067 DES_key_schedule user_schedule
; /* key schedule for user's key */
1068 afs_int32 tgskvno
; /* key version of service key */
1069 struct ktc_encryptionKey tgskey
; /* service key for encrypting ticket */
1071 afs_uint32 pwexpires
;
1073 COUNT_REQ(Authenticate
);
1074 if (!name_instance_legal(aname
, ainstance
))
1076 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1078 get_time(&now
, 0, 0);
1080 sname
= sinst
= NULL
;
1082 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1086 if (to
== 0) { /* no such user */
1091 /* have to check for locked before verifying the password, otherwise all
1092 * KALOCKED means is "yup, you guessed the password all right, now wait a
1093 * few minutes and we'll let you in"
1096 (to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
],
1097 (afs_uint32
) tentry
.misc_auth_bytes
[LOCKTIME
] << 9)) {
1103 save_principal(authPrincipal
, aname
, ainstance
, 0);
1105 /* decrypt request w/ user password */
1106 if ((code
= DES_key_sched(ktc_to_cblock(&tentry
.key
), &user_schedule
)))
1107 es_Report("In KAAuthenticate: key_sched returned %d\n", code
);
1108 DES_pcbc_encrypt(arequest
->SeqBody
, &request
,
1109 min(arequest
->SeqLen
, sizeof(request
)), &user_schedule
,
1110 ktc_to_cblockptr(&tentry
.key
), DECRYPT
);
1112 request
.time
= ntohl(request
.time
); /* reorder date */
1113 tgt
= !strncmp(request
.label
, KA_GETTGT_REQ_LABEL
, sizeof(request
.label
));
1114 adm
= !strncmp(request
.label
, KA_GETADM_REQ_LABEL
, sizeof(request
.label
));
1115 if (!(tgt
|| adm
)) {
1116 kaux_inc(to
, ((unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
]) << 9);
1117 code
= KABADREQUEST
;
1120 kaux_write(to
, 0, 0); /* reset counters */
1123 if (!tentry
.misc_auth_bytes
[EXPIRES
]) {
1124 /* 0 in the database means never, but 0 on the network means today */
1125 /* 255 on the network means "long time, maybe never" */
1128 pwexpires
= tentry
.misc_auth_bytes
[EXPIRES
];
1131 ntohl(tentry
.change_password_time
) + 24 * 60 * 60 * pwexpires
;
1132 if (adm
) { /* provide a little slack for admin ticket */
1133 pwexpires
+= 30 * 24 * 60 * 60; /* 30 days */
1135 if (pwexpires
< now
) {
1139 pwexpires
= (pwexpires
- now
) / (24 * 60 * 60);
1140 if (pwexpires
> 255)
1144 #endif /* EXPIREPW */
1146 if (check_ka_skew(request
.time
, now
, KTC_TIME_UNCERTAINTY
)) {
1148 if (oanswer
->MaxSeqLen
< sizeof(afs_int32
))
1149 code
= KAANSWERTOOLONG
;
1150 else { /* return our time if possible */
1151 oanswer
->SeqLen
= sizeof(afs_int32
);
1152 request
.time
= htonl(now
);
1153 memcpy(oanswer
->SeqBody
, &request
.time
, sizeof(afs_int32
));
1159 sname
= (tgt
? KA_TGS_NAME
: KA_ADMIN_NAME
);
1160 sinst
= (tgt
? lrealm
: KA_ADMIN_INST
);
1161 code
= FindBlock(tt
, sname
, sinst
, &to
, &server
);
1169 tgskvno
= ntohl(server
.key_version
);
1170 memcpy(&tgskey
, &server
.key
, sizeof(tgskey
));
1172 code
= DES_new_random_key(ktc_to_cblock(&sessionKey
));
1178 code
= GetEndTime(start
, end
, 0 /*!GetTicket */ , &tentry
, &server
, &end
);
1183 tkt_MakeTicket(ticket
, &ticketLen
, &tgskey
, aname
, ainstance
, "",
1184 start
, end
, &sessionKey
,
1185 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), sname
,
1193 ticketLen
+ sizeof(Date
) + sizeof(struct ktc_encryptionKey
) +
1194 2 * sizeof(afs_int32
) + KA_LABELSIZE
;
1195 answer_len
= round_up_to_ebs(answer_len
);
1196 if (answer_len
> oanswer
->MaxSeqLen
) {
1197 code
= KAANSWERTOOLONG
;
1200 oanswer
->SeqLen
= answer_len
;
1201 answer
= oanswer
->SeqBody
;
1202 answer_time
= htonl(request
.time
+ 1);
1203 memcpy(answer
, (char *)&answer_time
, sizeof(Date
));
1204 answer
+= sizeof(Date
);
1205 memcpy(answer
, (char *)&sessionKey
, sizeof(struct ktc_encryptionKey
));
1206 answer
+= sizeof(struct ktc_encryptionKey
);
1207 temp
= htonl(tgskvno
);
1208 memcpy(answer
, (char *)&temp
, sizeof(afs_int32
));
1209 answer
+= sizeof(afs_int32
);
1210 temp
= htonl(ticketLen
);
1211 memcpy(answer
, (char *)&temp
, sizeof(afs_int32
));
1212 answer
+= sizeof(afs_int32
);
1213 memcpy(answer
, ticket
, ticketLen
);
1214 answer
+= ticketLen
;
1215 memcpy(answer
, (tgt
? KA_GETTGT_ANS_LABEL
: KA_GETADM_ANS_LABEL
),
1221 PrepareTicketAnswer(oanswer
, request
.time
+ 1, ticket
, ticketLen
,
1222 &sessionKey
, start
, end
, &tentry
, &server
, "",
1223 (tgt
? KA_GETTGT_ANS_LABEL
:
1224 KA_GETADM_ANS_LABEL
));
1229 && oanswer
->SeqLen
< oanswer
->MaxSeqLen
+ sizeof(afs_int32
)) {
1230 temp
= pwexpires
<< 24; /* move it into the high byte */
1231 pwexpires
= htonl(temp
);
1233 memcpy((char *)oanswer
->SeqBody
+ oanswer
->SeqLen
, &pwexpires
,
1235 oanswer
->SeqLen
+= sizeof(afs_int32
);
1236 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1237 if (oanswer
->SeqLen
> oanswer
->MaxSeqLen
) {
1238 code
= KAANSWERTOOLONG
;
1242 #endif /* EXPIREPW */
1246 code
= KAINTERNALERROR
;
1249 DES_pcbc_encrypt(oanswer
->SeqBody
, oanswer
->SeqBody
, oanswer
->SeqLen
,
1250 &user_schedule
, ktc_to_cblockptr(&tentry
.key
), ENCRYPT
);
1251 code
= ubik_EndTrans(tt
);
1252 KALOG(aname
, ainstance
, sname
, sinst
, NULL
,
1253 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_AUTHENTICATE
);
1258 ubik_AbortTrans(tt
);
1259 KALOG(aname
, ainstance
, sname
, sinst
, NULL
,
1260 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_AUTHFAILED
);
1265 SKAA_Authenticate_old(struct rx_call
*call
, char *aname
, char *ainstance
,
1266 Date start
, Date end
, ka_CBS
*arequest
,
1271 IOMGR_Sleep(1); /* discourage use of this mechanism */
1273 Authenticate(0, call
, aname
, ainstance
, start
, end
, arequest
,
1275 osi_auditU(call
, AFS_KAA_AuthOEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1276 ainstance
, AUD_END
);
1282 SKAA_Authenticate(struct rx_call
*call
, char *aname
, char *ainstance
,
1283 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1288 Authenticate(1, call
, aname
, ainstance
, start
, end
, arequest
,
1290 osi_auditU(call
, AFS_KAA_AuthEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1291 ainstance
, AUD_END
);
1297 SKAA_AuthenticateV2(struct rx_call
*call
, char *aname
, char *ainstance
,
1298 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1303 Authenticate(2, call
, aname
, ainstance
, start
, end
, arequest
,
1305 osi_auditU(call
, AFS_KAA_AuthEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1306 ainstance
, AUD_END
);
1312 SKAM_SetFields(struct rx_call
*call
,
1317 afs_int32 alifetime
,
1318 afs_int32 amaxAssociates
,
1319 afs_uint32 misc_auth_bytes
, /* 4 bytes, each 0 means unspecified */
1325 kamSetFields(call
, aname
, ainstance
, aflags
, aexpiration
, alifetime
,
1326 amaxAssociates
, misc_auth_bytes
, spare2
);
1327 osi_auditU(call
, AFS_KAM_SetFldEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1328 ainstance
, AUD_LONG
, aflags
, AUD_DATE
, aexpiration
, AUD_LONG
,
1329 alifetime
, AUD_LONG
, amaxAssociates
, AUD_END
);
1334 kamSetFields(struct rx_call
*call
,
1339 afs_int32 alifetime
,
1340 afs_int32 amaxAssociates
,
1341 afs_uint32 misc_auth_bytes
, /* 4 bytes, each 0 means unspecified */
1346 struct ubik_trans
*tt
;
1348 afs_int32 tentry_offset
; /* offset of entry */
1349 struct kaentry tentry
;
1350 unsigned char newvals
[4];
1352 COUNT_REQ(SetFields
);
1355 return KABADARGUMENT
; /* not supported yet... */
1357 /* make sure we're supposed to do something */
1358 if (!(aflags
|| aexpiration
|| alifetime
|| (amaxAssociates
>= 0)
1360 || ((aflags
& ~KAFNORMAL
) & ~KAF_SETTABLE_FLAGS
))
1361 return KABADARGUMENT
; /* arguments no good */
1362 if (!name_instance_legal(aname
, ainstance
))
1364 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
1366 code
= check_auth(call
, tt
, 1, &caller
);
1371 code
= FindBlock(tt
, aname
, ainstance
, &tentry_offset
, &tentry
);
1374 if (tentry_offset
== 0) { /* no such user */
1378 if ((ntohl(tentry
.flags
) & KAFNORMAL
) == 0)
1379 return KAINTERNALERROR
;
1381 /* Keep track of the total number of admin accounts. This way we can
1382 * update database without any admin privilege initially */
1383 if ((aflags
& KAFADMIN
) != (ntohl(tentry
.flags
) & KAFADMIN
)) {
1384 /* if admin state is changing */
1386 if (ntohl(tentry
.flags
) & KAFADMIN
)
1390 if ((code
= update_admin_count(tt
, delta
)))
1394 htonl((ntohl(tentry
.flags
) & ~KAF_SETTABLE_FLAGS
) | aflags
);
1396 if ((code
= get_time(&now
, tt
, 1)))
1399 tentry
.user_expiration
= htonl(aexpiration
);
1400 if (!ntohl(tentry
.change_password_time
)) {
1401 tentry
.change_password_time
= htonl(now
);
1405 tentry
.max_ticket_lifetime
= htonl(alifetime
);
1407 #ifndef NOPWCONTROLS
1409 * We've packed a bunch of bytes into a long for backward compatibility.
1410 * These include password expiration time, and some failed login limits
1411 * counters. Now let's unpack them and stick them into the
1412 * kaentry struct. All the bytes have values in the range
1413 * 1..255, else they were not specified in the interface, and are
1415 * In the case of password expiration times, 1 means password never
1416 * expires (==>0), 2 means password only lives for one day (==>1),
1419 if (misc_auth_bytes
) {
1420 unpack_long(misc_auth_bytes
, newvals
);
1421 if (newvals
[EXPIRES
]) {
1422 tentry
.misc_auth_bytes
[EXPIRES
] = newvals
[EXPIRES
] - 1;
1425 if (newvals
[REUSEFLAGS
]) {
1426 if (newvals
[REUSEFLAGS
] & KA_REUSEPW
)
1427 memset(tentry
.pwsums
, 0, KA_NPWSUMS
);
1428 else if ((newvals
[REUSEFLAGS
] & KA_NOREUSEPW
)
1429 && !tentry
.pwsums
[0])
1430 tentry
.pwsums
[0] = 0xff;
1433 if (newvals
[ATTEMPTS
]) {
1434 tentry
.misc_auth_bytes
[ATTEMPTS
] = newvals
[ATTEMPTS
] - 1;
1436 if (newvals
[LOCKTIME
]) {
1437 tentry
.misc_auth_bytes
[LOCKTIME
] = newvals
[LOCKTIME
] - 1;
1440 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1443 #endif /* NOPWCONTROLS */
1445 if (amaxAssociates
>= 0) {
1446 if ((ntohl(tentry
.flags
) & KAFASSOC
)
1447 || (ntohl(tentry
.flags
) & KAFSPECIAL
))
1449 if (((ntohl(tentry
.flags
) & KAFASSOCROOT
) == 0) && (amaxAssociates
> 0)) /* convert normal user to assoc root */
1450 tentry
.flags
= htonl(ntohl(tentry
.flags
) | KAFASSOCROOT
);
1451 tentry
.misc
.assocRoot
.maxAssociates
= htonl(amaxAssociates
);
1454 tentry
.modification_time
= htonl(now
);
1455 tentry
.modification_id
= htonl(caller
);
1456 code
= kawrite(tt
, tentry_offset
, (char *) &tentry
, sizeof(tentry
));
1460 code
= ubik_EndTrans(tt
);
1461 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
,
1462 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_SETFIELDS
);
1467 ubik_AbortTrans(tt
);
1474 SKAM_DeleteUser(struct rx_call
*call
, char *aname
, char *ainstance
)
1478 code
= kamDeleteUser(call
, aname
, ainstance
);
1479 osi_auditU(call
, AFS_KAM_DelUserEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1480 ainstance
, AUD_END
);
1485 kamDeleteUser(struct rx_call
*call
, char *aname
, char *ainstance
)
1488 struct ubik_trans
*tt
;
1491 struct kaentry tentry
;
1492 unsigned int nfailures
;
1493 afs_uint32 locktime
;
1495 COUNT_REQ(DeleteUser
);
1496 if (!name_instance_legal(aname
, ainstance
))
1498 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
1500 code
= check_auth(call
, tt
, 1, &caller
);
1504 ubik_AbortTrans(tt
);
1508 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1511 if (to
== 0) { /* name not found */
1516 kaux_read(to
, &nfailures
, &locktime
);
1517 if (nfailures
|| locktime
)
1518 kaux_write(to
, 0, 0); /* zero failure counters at this offset */
1520 /* track all AuthServer identities */
1521 if (special_name(aname
, ainstance
))
1522 if ((code
= ka_DelKey(tt
, to
, &tentry
)))
1525 if (ntohl(tentry
.flags
) & KAFADMIN
) /* keep admin count up-to-date */
1526 if ((code
= update_admin_count(tt
, -1)))
1529 if ((code
= UnthreadBlock(tt
, &tentry
)) || (code
= FreeBlock(tt
, to
)) || (code
= get_time(0, tt
, 1)) /* update randomness */
1533 code
= ubik_EndTrans(tt
);
1534 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
,
1535 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_DELUSER
);
1539 /* we set a bit in here which indicates that the user's limit of
1540 * authentication failures has been exceeded. If that bit is not set,
1541 * kas can take it on faith that the user ID is not locked. If that
1542 * bit is set, kas has to check all the servers to find one who will
1543 * report that the ID is not locked, or else to find out when the ID
1547 SKAM_GetEntry(struct rx_call
*call
,
1550 afs_int32 aversion
, /* major version assumed by caller */
1551 kaentryinfo
*aentry
) /* entry data copied here */
1555 code
= kamGetEntry(call
, aname
, ainstance
, aversion
, aentry
);
1556 osi_auditU(call
, AFS_KAM_GetEntEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1557 ainstance
, AUD_END
);
1562 kamGetEntry(struct rx_call
*call
,
1565 afs_int32 aversion
, /* major version assumed by caller */
1566 kaentryinfo
*aentry
) /* entry data copied here */
1569 struct ubik_trans
*tt
;
1570 afs_int32 callerIndex
;
1571 struct kaentry caller
;
1574 struct kaentry tentry
;
1575 rxkad_level enc_level
= rxkad_clear
;
1576 int callerIsAdmin
= 0;
1578 COUNT_REQ(GetEntry
);
1579 if (aversion
!= KAMAJORVERSION
)
1580 return KAOLDINTERFACE
;
1581 if (!name_instance_legal(aname
, ainstance
))
1583 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1585 code
= check_auth(call
, tt
, 0, &callerIndex
);
1589 if (noAuthenticationRequired
) {
1590 } else if (!callerIndex
) {
1594 if ((code
= karead(tt
, callerIndex
, (char *)&caller
, sizeof(caller
)))) {
1598 /* if the user is checking his own entry or ADMIN then go ahead. */
1599 callerIsAdmin
= (ntohl(caller
.flags
) & KAFADMIN
);
1601 if (strcmp(caller
.userID
.name
, aname
) != 0 && !callerIsAdmin
) {
1607 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1610 if (to
== 0) { /* entry not found */
1615 get_time(0, 0, 0); /* generate random update */
1617 memset(aentry
, 0, sizeof(*aentry
));
1618 aentry
->minor_version
= KAMINORVERSION
;
1619 aentry
->flags
= ntohl(tentry
.flags
);
1620 aentry
->user_expiration
= ntohl(tentry
.user_expiration
);
1621 aentry
->modification_time
= ntohl(tentry
.modification_time
);
1622 aentry
->change_password_time
= ntohl(tentry
.change_password_time
);
1623 aentry
->max_ticket_lifetime
= ntohl(tentry
.max_ticket_lifetime
);
1624 aentry
->key_version
= ntohl(tentry
.key_version
);
1626 temp
= (unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
];
1628 if (kaux_islocked(to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
], temp
))
1629 tentry
.misc_auth_bytes
[REUSEFLAGS
] |= KA_ISLOCKED
; /* saves an RPC */
1631 temp
= pack_long(tentry
.misc_auth_bytes
);
1632 aentry
->misc_auth_bytes
= temp
;
1634 * only return user's key if security disabled or if admin and
1635 * we have an encrypted connection to the user
1637 rxkad_GetServerInfo(rx_ConnectionOf(call
), &enc_level
, 0, 0, 0, 0, 0);
1638 if ((noAuthenticationRequired
)
1639 || (callerIsAdmin
&& enc_level
== rxkad_crypt
))
1640 memcpy(&aentry
->key
, &tentry
.key
, sizeof(struct ktc_encryptionKey
));
1642 memset(&aentry
->key
, 0, sizeof(aentry
->key
));
1644 code
= ka_KeyCheckSum((char *)&tentry
.key
, &aentry
->keyCheckSum
);
1648 if (!tentry
.pwsums
[0] && npwSums
> 1 && !tentry
.pwsums
[1]) {
1649 aentry
->reserved3
= 0x12340000;
1651 aentry
->reserved3
= 0x12340001;
1654 /* Now get entry of user who last modified this entry */
1655 if (ntohl(tentry
.modification_id
)) {
1656 temp
= ntohl(tentry
.modification_id
);
1657 code
= karead(tt
, temp
, (char *)&tentry
, sizeof(tentry
));
1662 aentry
->modification_user
= tentry
.userID
;
1664 strcpy(aentry
->modification_user
.name
, "<none>");
1665 strcpy(aentry
->modification_user
.instance
, "\0");
1667 code
= ubik_EndTrans(tt
);
1672 ubik_AbortTrans(tt
);
1677 SKAM_ListEntry(struct rx_call
*call
,
1678 afs_int32 previous_index
, /* last entry ret'd or 0 for first */
1679 afs_int32
*index
, /* index of this entry */
1680 afs_int32
*count
, /* total entries in database */
1681 kaident
*name
) /* name & instance of this entry */
1685 code
= kamListEntry(call
, previous_index
, index
, count
, name
);
1686 osi_auditU(call
, AFS_KAM_LstEntEvent
, code
, AUD_LONG
, *index
, AUD_END
);
1692 kamListEntry(struct rx_call
*call
,
1693 afs_int32 previous_index
, /* last entry ret'd or 0 for first */
1694 afs_int32
*index
, /* index of this entry */
1695 afs_int32
*count
, /* total entries in database */
1696 kaident
*name
) /* name & instance of this entry */
1699 struct ubik_trans
*tt
;
1701 struct kaentry tentry
;
1703 COUNT_REQ(ListEntry
);
1704 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1706 code
= check_auth(call
, tt
, 1, &caller
);
1711 *index
= NextBlock(tt
, previous_index
, &tentry
, count
);
1717 if (*index
) { /* return name & inst of this entry */
1718 strncpy(name
->name
, tentry
.userID
.name
, sizeof(name
->name
));
1719 strncpy(name
->instance
, tentry
.userID
.instance
,
1720 sizeof(name
->instance
));
1722 strcpy(name
->name
, "\0");
1723 strcpy(name
->instance
, "\0");
1725 code
= ubik_EndTrans(tt
);
1730 ubik_AbortTrans(tt
);
1735 GetTicket(int version
,
1736 struct rx_call
*call
,
1742 ka_CBS
*atimes
, /* encrypted start & end time */
1747 struct ubik_trans
*tt
;
1748 struct ktc_encryptionKey tgskey
;
1749 DES_key_schedule schedule
;
1751 char name
[MAXKTCNAMELEN
];
1752 char instance
[MAXKTCNAMELEN
];
1753 char cell
[MAXKTCNAMELEN
];
1755 struct kaentry caller
;
1756 struct kaentry server
;
1757 struct ktc_encryptionKey authSessionKey
;
1758 struct ktc_encryptionKey sessionKey
;
1760 char ticket
[MAXKTCTICKETLEN
];
1766 struct ka_getTicketTimes times
;
1767 struct ka_getTicketAnswer
*answer
;
1769 COUNT_REQ(GetTicket
);
1770 if (!name_instance_legal(sname
, sinstance
))
1772 if (atimes
->SeqLen
!= sizeof(times
))
1773 return KABADARGUMENT
;
1774 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1777 export
= import
= 0;
1778 if ((strcmp(sname
, KA_TGS_NAME
) == 0) && (strcmp(sinstance
, lrealm
) != 0))
1780 if ((strlen(authDomain
) > 0) && (strcmp(authDomain
, lrealm
) != 0))
1783 if (strlen(authDomain
) == 0)
1784 authDomain
= lrealm
;
1785 code
= ka_LookupKvno(tt
, KA_TGS_NAME
, authDomain
, kvno
, &tgskey
);
1790 tkt_DecodeTicket(aticket
->SeqBody
, aticket
->SeqLen
, &tgskey
, name
,
1791 instance
, cell
, &authSessionKey
, &host
, &start
,
1797 save_principal(tgsPrincipal
, name
, instance
, cell
);
1799 if ((code
= get_time(&now
, 0, 0)))
1802 code
= tkt_CheckTimes(start
, expiration
, now
);
1805 code
= RXKADEXPIRED
;
1810 code
= DES_key_sched(ktc_to_cblock(&authSessionKey
), &schedule
);
1815 celllen
= strlen(cell
);
1816 if (import
&& (celllen
== 0)) {
1820 if (export
&& (celllen
== 0))
1821 strcpy(cell
, lrealm
);
1823 if (!krb4_cross
&& celllen
&& strcmp(lrealm
, cell
) != 0) {
1828 DES_ecb_encrypt((DES_cblock
*)atimes
->SeqBody
, (DES_cblock
*)×
, &schedule
, DECRYPT
);
1829 times
.start
= ntohl(times
.start
);
1830 times
.end
= ntohl(times
.end
);
1831 code
= tkt_CheckTimes(times
.start
, times
.end
, now
);
1833 code
= KABADREQUEST
;
1838 strcpy(caller
.userID
.name
, name
);
1839 strcpy(caller
.userID
.instance
, instance
);
1840 caller
.max_ticket_lifetime
= htonl(MAXKTCTICKETLIFETIME
);
1841 caller
.flags
= htonl(KAFNORMAL
);
1842 caller
.user_expiration
= htonl(NEVERDATE
);
1844 code
= FindBlock(tt
, name
, instance
, &to
, &caller
);
1848 ka_PrintUserID("GetTicket: User ", name
, instance
, " unknown.\n");
1854 /* get server's entry */
1855 code
= FindBlock(tt
, sname
, sinstance
, &to
, &server
);
1858 if (to
== 0) { /* entry not found */
1859 ka_PrintUserID("GetTicket: Server ", sname
, sinstance
, " unknown.\n");
1863 save_principal(tgsServerPrincipal
, sname
, sinstance
, 0);
1865 code
= DES_new_random_key(ktc_to_cblock(&sessionKey
));
1872 GetEndTime(times
.start
, times
.end
, expiration
, &caller
, &server
,
1878 tkt_MakeTicket(ticket
, &ticketLen
, &server
.key
, caller
.userID
.name
,
1879 caller
.userID
.instance
, cell
, times
.start
, end
,
1881 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))),
1882 server
.userID
.name
, server
.userID
.instance
);
1888 code
= KAANSWERTOOLONG
;
1889 if (oanswer
->MaxSeqLen
<
1890 sizeof(struct ka_getTicketAnswer
) - 5 * MAXKTCNAMELEN
-
1891 MAXKTCTICKETLEN
+ ticketLen
)
1894 answer
= (struct ka_getTicketAnswer
*)oanswer
->SeqBody
;
1895 memcpy(&answer
->sessionKey
, &sessionKey
,
1896 sizeof(struct ktc_encryptionKey
));
1897 answer
->startTime
= htonl(times
.start
);
1898 answer
->endTime
= htonl(end
);
1899 answer
->kvno
= server
.key_version
;
1900 answer
->ticketLen
= htonl(ticketLen
);
1903 char *ans
= answer
->name
; /* ptr to variable part of answer */
1906 /* space remaining */
1907 rem
= oanswer
->MaxSeqLen
- (ans
- oanswer
->SeqBody
);
1909 #define putstr(str) len = strlen (str)+1;\
1910 if (rem < len) goto abort;\
1912 ans += len; rem -= len
1919 if (rem
< ticketLen
)
1921 memcpy(ans
, ticket
, ticketLen
);
1922 oanswer
->SeqLen
= (ans
- oanswer
->SeqBody
) + ticketLen
;
1924 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1928 PrepareTicketAnswer(oanswer
, /*challenge */ 0, ticket
, ticketLen
,
1929 &sessionKey
, times
.start
, end
, &caller
,
1930 &server
, cell
, KA_GETTICKET_ANS_LABEL
);
1935 code
= KAINTERNALERROR
;
1938 DES_pcbc_encrypt(oanswer
->SeqBody
, oanswer
->SeqBody
, oanswer
->SeqLen
,
1939 &schedule
, ktc_to_cblockptr(&authSessionKey
), ENCRYPT
);
1940 code
= ubik_EndTrans(tt
);
1941 KALOG(name
, instance
, sname
, sinstance
, (import
? authDomain
: NULL
),
1942 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_GETTICKET
);
1947 ubik_AbortTrans(tt
);
1952 SKAT_GetTicket_old(struct rx_call
*call
,
1958 ka_CBS
*atimes
, /* encrypted start & end time */
1963 sleep(1); /* strongly discourage this */
1965 GetTicket(0, call
, kvno
, authDomain
, aticket
, sname
, sinstance
,
1968 osi_auditU(call
, AFS_KAT_GetTicketOEvent
, code
, AUD_STR
, sname
, AUD_STR
,
1969 sinstance
, AUD_END
);
1974 SKAT_GetTicket(struct rx_call
*call
,
1980 ka_CBS
*atimes
, /* encrypted start & end time */
1986 GetTicket(1, call
, kvno
, authDomain
, aticket
, sname
, sinstance
,
1988 osi_auditU(call
, AFS_KAT_GetTicketEvent
, code
, AUD_STR
, sname
, AUD_STR
,
1989 sinstance
, AUD_END
);
1994 SKAM_GetStats(struct rx_call
*call
, afs_int32 version
,
1995 afs_int32
*admin_accounts
, kasstats
*statics
,
2000 code
= kamGetStats(call
, version
, admin_accounts
, statics
, dynamics
);
2001 osi_auditU(call
, AFS_KAM_GetStatEvent
, code
, AUD_END
);
2006 kamGetStats(struct rx_call
*call
, afs_int32 version
,
2007 afs_int32
*admin_accounts
, kasstats
*statics
,
2011 struct ubik_trans
*tt
;
2014 COUNT_REQ(GetStats
);
2015 if (version
!= KAMAJORVERSION
)
2016 return KAOLDINTERFACE
;
2017 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2019 code
= check_auth(call
, tt
, 1, &caller
);
2022 ubik_AbortTrans(tt
);
2026 *admin_accounts
= ntohl(cheader
.admin_accounts
);
2027 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2028 /* these are stored in network byte order and must be copied */
2029 statics
->allocs
= ntohl(cheader
.stats
.allocs
);
2030 statics
->frees
= ntohl(cheader
.stats
.frees
);
2031 statics
->cpws
= ntohl(cheader
.stats
.cpws
);
2032 #if KADBVERSION != 5
2033 check that the statistics command copies all the fields
2035 memcpy((char *)dynamics
, (char *)&dynamic_statistics
, sizeof(kadstats
));
2036 statics
->minor_version
= KAMINORVERSION
;
2037 dynamics
->minor_version
= KAMINORVERSION
;
2043 for (i
= 0; i
< HASHSIZE
; i
++)
2044 if (cheader
.nameHash
[i
])
2046 dynamics
->hashTableUtilization
=
2047 (used
* 10000 + HASHSIZE
/ 2) / HASHSIZE
;
2050 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2052 /* Unfortunately, although aix_22 has a minimal compatibility
2053 * method of getting to some rusage fields (i.e. stime &
2054 * utime), the version that we have doesn't even have the
2055 * related include files needed for the aix vtimes() call; so
2056 * ignore this for aix till v3.1... */
2057 getrusage(RUSAGE_SELF
, &ru
);
2058 #if (KAMAJORVERSION>5)
2059 memcpy(&dynamics
->utime
, &ru
.ru_utime
, sizeof(struct katimeval
));
2060 memcpy(&dynamics
->stime
, &ru
.ru_stime
, sizeof(struct katimeval
));
2061 dynamics
->dataSize
= ru
.ru_idrss
;
2062 dynamics
->stackSize
= ru
.ru_isrss
;
2063 dynamics
->pageFailts
= ru
.ru_majflt
;
2065 dynamics
->string_checks
=
2066 (afs_int32
) (1000.0 *
2067 ((ru
.ru_utime
.tv_sec
+
2068 ru
.ru_utime
.tv_usec
/ 1000000.0) +
2069 (ru
.ru_stime
.tv_sec
+
2070 ru
.ru_stime
.tv_usec
/ 1000000.0)));
2072 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2075 code
= ubik_EndTrans(tt
);
2080 SKAM_GetPassword(struct rx_call
*call
, char *name
, EncryptionKey
*password
)
2084 code
= kamGetPassword(call
, name
, password
);
2085 osi_auditU(call
, AFS_KAM_GetPswdEvent
, code
, AUD_STR
, name
, AUD_END
);
2090 kamGetPassword(struct rx_call
*call
, char *name
, EncryptionKey
*password
)
2092 int code
= KANOAUTH
;
2093 AFS_UNUSED
COUNT_REQ(GetPassword
);
2097 struct ubik_trans
*tt
;
2098 struct kaentry tentry
;
2100 if (!name_instance_legal(name
, ""))
2102 /* only requests from this host work */
2103 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))) !=
2104 htonl(INADDR_LOOPBACK
))
2106 if (code
= InitAuthServ(&tt
, LOCKREAD
, this_op
))
2109 /* this isn't likely to be used because of string to key problems, so since
2110 * this is a temporary thing anyway, we'll use it here. */
2112 extern char udpAuthPrincipal
[256];
2114 save_principal(udpAuthPrincipal
, name
, 0, 0);
2117 get_time(0, 0, 0); /* update random value */
2118 code
= FindBlock(tt
, name
, "", &to
, &tentry
);
2125 ubik_AbortTrans(tt
);
2129 memcpy(password
, &tentry
.key
, sizeof(*password
));
2130 code
= ubik_EndTrans(tt
);
2137 SKAM_GetRandomKey(struct rx_call
*call
, EncryptionKey
*key
)
2141 code
= kamGetRandomKey(call
, key
);
2142 osi_auditU(call
, AFS_KAM_GetRndKeyEvent
, code
, AUD_END
);
2147 kamGetRandomKey(struct rx_call
*call
, EncryptionKey
*key
)
2151 AFS_UNUSED
COUNT_REQ(GetRandomKey
);
2152 if ((code
= AwaitInitialization()))
2154 code
= DES_new_random_key(EncryptionKey_to_cblock(key
));
2161 SKAM_Debug(struct rx_call
*call
,
2163 int checkDB
, /* start a transaction to examine DB */
2164 struct ka_debugInfo
*info
)
2168 code
= kamDebug(call
, version
, checkDB
, info
);
2169 osi_auditU(call
, AFS_KAM_DbgEvent
, code
, AUD_END
);
2174 kamDebug(struct rx_call
*call
,
2176 int checkDB
, /* start a transaction to examine DB */
2177 struct ka_debugInfo
*info
)
2179 /* COUNT_REQ (Debug); */
2180 if (sizeof(struct kaentry
) != sizeof(struct kaOldKeys
))
2181 return KAINTERNALERROR
;
2182 if (sizeof(struct ka_cpwRequest
) % 8)
2183 return KAINTERNALERROR
;
2184 if (version
!= KAMAJORVERSION
)
2185 return KAOLDINTERFACE
;
2187 memset(info
, 0, sizeof(*info
));
2189 info
->minorVersion
= KAMINORVERSION
;
2190 info
->host
= dynamic_statistics
.host
;
2191 info
->startTime
= dynamic_statistics
.start_time
;
2193 #if (KAMAJORVERSION>5)
2199 info
->noAuth
= noAuthenticationRequired
;
2201 info
->dbVersion
= ntohl(cheader
.version
);
2202 info
->dbFreePtr
= ntohl(cheader
.freePtr
);
2203 info
->dbEofPtr
= ntohl(cheader
.eofPtr
);
2204 info
->dbKvnoPtr
= ntohl(cheader
.kvnoPtr
);
2205 info
->dbSpecialKeysVersion
= ntohl(cheader
.specialKeysVersion
);
2207 info
->dbHeaderRead
= cheaderReadTime
;
2208 info
->lastTrans
= lastTrans
;
2210 lastOperation
= "(Not Available)";
2211 strncpy(info
->lastOperation
, lastOperation
, sizeof(info
->lastOperation
));
2212 strncpy(info
->lastAuth
, authPrincipal
, sizeof(info
->lastAuth
));
2213 strncpy(info
->lastTGS
, tgsPrincipal
, sizeof(info
->lastTGS
));
2214 strncpy(info
->lastAdmin
, adminPrincipal
, sizeof(info
->lastAdmin
));
2215 strncpy(info
->lastTGSServer
, tgsServerPrincipal
,
2216 sizeof(info
->lastTGSServer
));
2218 extern char udpAuthPrincipal
[256];
2219 extern char udptgsPrincipal
[256];
2220 extern char udptgsServerPrincipal
[256];
2222 strncpy(info
->lastUAuth
, udpAuthPrincipal
, sizeof(info
->lastUAuth
));
2223 strncpy(info
->lastUTGS
, udptgsPrincipal
, sizeof(info
->lastUTGS
));
2224 strncpy(info
->lastUTGSServer
, udptgsServerPrincipal
,
2225 sizeof(info
->lastUTGSServer
));
2227 info
->nextAutoCPW
= nextAutoCPWTime
;
2228 info
->updatesRemaining
= autoCPWUpdates
- totalUpdates
;
2229 ka_debugKeyCache(info
);
2233 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2234 * a tacked-on-the-side data file.
2235 * prob'ly ought to check the noauth flag.
2237 #define ABORTIF(A) {if((code = A)){goto abort;}}
2239 SKAM_Unlock(struct rx_call
*call
,
2248 struct ubik_trans
*tt
;
2251 struct kaentry tentry
;
2254 if (!name_instance_legal(aname
, ainstance
)) {
2258 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2261 ABORTIF(check_auth(call
, tt
, 1, &caller
));
2262 ABORTIF(FindBlock(tt
, aname
, ainstance
, &to
, &tentry
));
2263 ABORTIF((to
== 0 ? KANOENT
: 0));
2265 kaux_write(to
, 0, 0); /* zero failure counters at this offset */
2267 code
= ubik_EndTrans(tt
);
2268 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
,
2269 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), LOG_UNLOCK
);
2274 ubik_AbortTrans(tt
);
2277 osi_auditU(call
, UnlockEvent
, code
, AUD_STR
, aname
, AUD_STR
, ainstance
,
2283 SKAM_LockStatus(struct rx_call
*call
,
2286 afs_int32
*lockeduntil
,
2293 struct ubik_trans
*tt
;
2294 afs_int32 callerIndex
;
2296 struct kaentry caller
;
2297 struct kaentry tentry
;
2300 COUNT_REQ(LockStatus
);
2302 if (!name_instance_legal(aname
, ainstance
)) {
2306 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2309 if ((code
= check_auth(call
, tt
, 0, &callerIndex
)))
2312 if (!noAuthenticationRequired
&& callerIndex
) {
2313 if (karead(tt
, callerIndex
, (char *)&caller
, sizeof(caller
))) {
2317 /* if the user is checking his own entry or ADMIN then go ahead. */
2318 if ((strcmp(caller
.userID
.name
, aname
) != 0)
2319 && !(ntohl(caller
.flags
) & KAFADMIN
)) {
2325 if ((code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
)))
2333 temp
= (unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
];
2336 kaux_islocked(to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
], temp
);
2338 code
= ubik_EndTrans(tt
);
2343 ubik_AbortTrans(tt
);
2344 osi_auditU(call
, LockStatusEvent
, code
, AUD_STR
, aname
, AUD_STR
,
2345 ainstance
, AUD_END
);