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 #include <sys/types.h>
20 #include <afs/afsutil.h>
22 #include <sys/resource.h>
30 #include <des_prototypes.h>
37 #include <netinet/in.h>
40 #include <afs/cellconfig.h>
42 #include <afs/com_err.h>
47 #include "kauth_internal.h"
48 #include "afs/audit.h"
50 #include "kadatabase.h"
53 extern struct ubik_dbase
*KA_dbase
;
54 struct kaheader cheader
;
55 Date cheaderReadTime
; /* time cheader last read in */
56 extern struct afsconf_dir
*KA_conf
; /* for getting cell info */
60 char lrealm
[MAXKTCREALMLEN
];
62 #ifndef EXPIREPW /* password expiration default yes */
66 #ifndef AUTOCPWINTERVAL
67 #define AUTOCPWINTERVAL (24*3600)
69 #ifndef AUTOCPWUPDATES
70 #define AUTOCPWUPDATES 128
75 static afs_int32 autoCPWInterval
;
76 static afs_int32 autoCPWUpdates
;
78 static afs_int32
set_password(struct ubik_trans
*tt
, char *name
,
80 struct ktc_encryptionKey
*password
,
81 afs_int32 kvno
, afs_int32 caller
);
82 static afs_int32
impose_reuse_limits(EncryptionKey
*password
,
83 struct kaentry
*tentry
);
84 static int create_user(struct ubik_trans
*tt
, char *name
, char *instance
,
85 struct ktc_encryptionKey
*key
, afs_int32 caller
,
88 /* This routine is called whenever an RPC interface needs the time. It uses
89 the current time to randomize a 128 bit value that is used to change the
90 AuthServer Admin and TGS keys automatically. */
92 static Date nextAutoCPWTime
= 0;
93 static afs_int32 totalUpdates
= 0;
95 /* This routine is ostensibly to get the current time, but basically its job is
96 to periodically update a random number. It also periodically updates the
97 keys for the builtin servers. This is why it needs a transaction pointer
98 and returns an error code. If the caller is in a read transaction, the tt
99 ptr should be zero and the return code need not be checked. */
102 get_time(Date
*timeP
,
103 struct ubik_trans
*tt
, /* tt != 0: a write transaction */
104 int admin
) /* the caller is an admin user */
106 /* random value used to change Admin & TGS keys, this is at risk during
107 * multi-threaded operation, but I think the consequences are fairly
109 static afs_uint32 random_value
[4];
112 unsigned int bit
, nbit
;
116 gettimeofday(&time
, 0);
117 bit
= (random_value
[3] >> 31) & 1; /* get high bit of high word */
118 for (i
= 0; i
< 4; i
++) {
119 nbit
= random_value
[i
] >> 31;
120 random_value
[i
] = (random_value
[i
] << 1) + bit
;
123 /* get 60ths from usec. This is all the real randomness there is. */
124 random_value
[0] += time
.tv_usec
/ 16667;
126 if (nextAutoCPWTime
== 0) { /* initialize things */
127 nextAutoCPWTime
= time
.tv_sec
+ autoCPWInterval
;
128 memcpy(&random_value
[0], &time
, 8);
129 memcpy(&random_value
[2], &time
, 8);
132 if ((++totalUpdates
>= autoCPWUpdates
) && tt
&& /* a write transaction */
133 ((admin
&& (time
.tv_sec
>= nextAutoCPWTime
))
134 || (time
.tv_sec
>= nextAutoCPWTime
+ autoCPWInterval
))) {
135 struct ktc_encryptionKey key
;
136 char buf
[4 * sizeof(key
) + 1];
137 struct kaentry tentry
;
139 char bob
[KA_TIMESTR_LEN
];
141 ka_timestr(time
.tv_sec
, bob
, KA_TIMESTR_LEN
);
142 es_Report("Auto CPW at %s\n", bob
);
144 es_Report(" ... even though no ADMIN user\n");
146 code
= FindBlock(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &to
, &tentry
);
149 if (to
) { /* check if auto cpw is disabled */
150 if (!(ntohl(tentry
.flags
) & KAFNOCPW
)) {
151 memcpy(&key
, &random_value
[0], sizeof(key
));
152 des_fixup_key_parity(ktc_to_cblock(&key
));
154 set_password(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &key
, 0,
157 des_init_random_number_generator(ktc_to_cblock(&key
));
158 ka_ConvertBytes(buf
, sizeof(buf
), (char *)&key
,
160 es_Report("New Admin key is %s\n", buf
);
163 ("in get_time: set_password failed because: %d\n",
170 code
= FindBlock(tt
, KA_TGS_NAME
, lrealm
, &to
, &tentry
);
173 if (to
) { /* check if auto cpw is disabled */
174 if (!(ntohl(tentry
.flags
) & KAFNOCPW
)) {
175 memcpy(&key
, &random_value
[2], sizeof(key
));
176 des_fixup_key_parity(ktc_to_cblock(&key
));
177 code
= set_password(tt
, KA_TGS_NAME
, lrealm
, &key
, 0, 0);
179 ka_ConvertBytes(buf
, sizeof(buf
), (char *)&key
,
181 es_Report("New TGS key is %s\n", buf
);
184 ("in get_time: set_password failed because: %s\n",
185 afs_error_message(code
));
190 code
= ka_FillKeyCache(tt
); /* ensure in-core copy is uptodate */
194 nextAutoCPWTime
= time
.tv_sec
+ autoCPWInterval
;
198 *timeP
= time
.tv_sec
;
202 static int noAuthenticationRequired
; /* global state */
203 static int recheckNoAuth
; /* global state */
205 /* kaprocsInited is sort of a lock: during a transaction only one process runs
206 while kaprocsInited is false. */
208 static int kaprocsInited
= 0;
210 /* This variable is protected by the kaprocsInited flag. */
212 static int (*rebuildDatabase
) (struct ubik_trans
*);
214 /* This is called to initialize the database */
217 initialize_database(struct ubik_trans
*tt
)
219 struct ktc_encryptionKey key
;
222 gettimeofday((struct timeval
*)&key
, 0); /* this is just a cheap seed key */
223 des_fixup_key_parity(ktc_to_cblock(&key
));
224 des_init_random_number_generator(ktc_to_cblock(&key
));
225 if ((code
= des_random_key(ktc_to_cblock(&key
)))
227 create_user(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &key
, 0,
228 KAFNORMAL
| KAFNOSEAL
| KAFNOTGS
)))
230 if ((code
= des_random_key(ktc_to_cblock(&key
)))
232 create_user(tt
, KA_TGS_NAME
, lrealm
, &key
, 0,
233 KAFNORMAL
| KAFNOSEAL
| KAFNOTGS
)))
238 /* This routine handles initialization required by this module. The initFlags
239 parameter passes some information about the command line arguments. */
242 init_kaprocs(const char *lclpath
, int initFlags
)
245 struct ubik_trans
*tt
;
246 struct ktc_encryptionKey key
;
251 return KAINTERNALERROR
;
253 return KAINTERNALERROR
;
254 code
= afsconf_GetLocalCell(KA_conf
, lrealm
, sizeof(lrealm
));
256 printf("** Can't determine local cell name!\n");
259 ucstring(lrealm
, lrealm
, sizeof(lrealm
));
263 noAuthenticationRequired
= 1;
267 noAuthenticationRequired
= afsconf_GetNoAuthFlag(KA_conf
);
268 if (noAuthenticationRequired
)
269 printf("Running server with security disabled\n");
272 autoCPWInterval
= 10;
275 autoCPWInterval
= AUTOCPWINTERVAL
;
276 autoCPWUpdates
= AUTOCPWUPDATES
;
279 init_kadatabase(initFlags
);
280 rebuildDatabase
= initialize_database
;
282 if ((code
= InitAuthServ(&tt
, LOCKREAD
, 0))) {
283 printf("init_kaprocs: InitAuthServ failed: code = %d\n", code
);
286 code
= ka_LookupKey(tt
, KA_ADMIN_NAME
, KA_ADMIN_INST
, &kvno
, &key
);
290 ("init_kaprocs: ka_LookupKey (code = %d) DB not initialized properly?\n",
294 des_init_random_number_generator(ktc_to_cblock(&key
));
296 code
= ubik_EndTrans(tt
);
298 printf("init_kaprocs: ubik_EndTrans failed: code = %d\n", code
);
302 kaux_opendb((char *)lclpath
);/* aux database stores failure counters */
303 rebuildDatabase
= 0; /* only do this during init */
308 /* These variable are for returning debugging info about the state of the
309 server. If they get trashed during multi-threaded operation it doesn't
312 /* this is global so COUNT_REQ in krb_udp.c can refer to it. */
313 char *lastOperation
= 0; /* name of last operation */
314 static Date lastTrans
; /* time of last transaction */
316 static char adminPrincipal
[256];
317 static char authPrincipal
[256];
318 static char tgsPrincipal
[256];
319 static char tgsServerPrincipal
[256];
322 save_principal(char *p
, char *n
, char *i
, char *c
)
332 if (i
&& strlen(i
)) {
342 if (c
&& strlen(c
)) {
354 check_auth(struct rx_call
*call
,
355 struct ubik_trans
*at
,
356 int admin
, /* require caller to be ADMIN */
357 afs_int32
*acaller_id
)
360 char name
[MAXKTCNAMELEN
];
361 char instance
[MAXKTCNAMELEN
];
362 char cell
[MAXKTCREALMLEN
];
364 Date expiration
; /* checked by Security Module */
365 struct kaentry tentry
;
372 noAuthenticationRequired
= afsconf_GetNoAuthFlag(KA_conf
);
374 si
= rx_SecurityClassOf(rx_ConnectionOf(call
));
375 if (si
== RX_SCINDEX_VAB
) {
376 printf("No support for VAB security module yet.\n");
378 } else if (si
== RX_SCINDEX_NULL
) {
381 } else if (si
!= RX_SCINDEX_KAD
) {
382 es_Report("Unknown security index %d\n", si
);
387 rxkad_GetServerInfo(rx_ConnectionOf(call
), &level
, &expiration
, name
,
388 instance
, cell
, &kvno
);
392 if (level
!= rxkad_crypt
) {
393 es_Report("Incorrect security level = %d\n", level
);
398 if (!name_instance_legal(name
, instance
))
402 ("Authorization rejected because we don't understand intercell stuff yet: ",
404 printf("@%s\n", cell
);
408 code
= FindBlock(at
, name
, instance
, acaller_id
, &tentry
);
411 if (*acaller_id
== 0) {
412 ka_PrintUserID("User ", name
, instance
, " unknown.\n");
415 save_principal(adminPrincipal
, name
, instance
, 0);
418 if (!(ntohl(tentry
.flags
) & KAFADMIN
)) {
419 if (noAuthenticationRequired
) {
420 ka_PrintUserID("Authorization approved for ", name
, instance
,
421 " because there is no authentication required\n");
422 osi_auditU(call
, UnAuthEvent
, code
, AUD_STR
, name
, AUD_STR
,
423 instance
, AUD_STR
, cell
, AUD_END
);
426 ka_PrintUserID("User ", name
, instance
, " is not ADMIN.\n");
429 osi_auditU(call
, UseOfPrivilegeEvent
, code
, AUD_STR
, name
, AUD_STR
,
430 instance
, AUD_STR
, cell
, AUD_END
);
435 if (noAuthenticationRequired
) {
437 ("Caller w/o authorization approved no authentication required\n");
438 osi_auditU(call
, UnAuthEvent
, code
, AUD_STR
, name
, AUD_STR
, instance
,
439 AUD_STR
, cell
, AUD_END
);
442 return code
; /* no auth info */
446 AwaitInitialization(void)
449 while (!kaprocsInited
) {
452 else if (time(0) - start
> 5)
459 /* This is called by every RPC interface to create a Ubik transaction and read
460 the database header into core */
463 InitAuthServ(struct ubik_trans
**tt
,
464 int lock
, /* indicate read/write transaction */
465 int *this_op
) /* opcode of RPC proc, for COUNT_ABO */
468 afs_int32 start
= 0; /* time started waiting for quorum */
469 float wait
= 0.91; /* start waiting for 1 second */
471 /* Wait for server initialization to finish if not during init_kaprocs */
473 if ((code
= AwaitInitialization()))
476 for (code
= UNOQUORUM
; code
== UNOQUORUM
;) {
477 if (lock
== LOCKREAD
)
478 code
= ubik_BeginTransReadAny(KA_dbase
, UBIK_READTRANS
, tt
);
480 code
= ubik_BeginTrans(KA_dbase
, UBIK_WRITETRANS
, tt
);
481 if (code
== UNOQUORUM
) { /* no quorum elected */
485 int delay
= time(0) - start
;
486 if (this_op
) { /* punt quickly, if RPC call */
489 } else { /* more patient during init. */
494 printf("Waiting for quorum election.\n");
497 IOMGR_Sleep((int)wait
);
502 if ((code
= ubik_SetLock(*tt
, 1, 1, lock
))) {
505 ubik_AbortTrans(*tt
);
508 /* check that dbase is initialized and setup cheader */
509 if (lock
== LOCKREAD
) {
510 /* init but don't fix because this is read only */
511 code
= CheckInit(*tt
, 0);
513 ubik_AbortTrans(*tt
); /* abort, since probably I/O error */
514 /* we did the check under a ReadAny transaction, but now, after
515 * getting a write transaction (and thus some real guarantees
516 * about what databases are really out there), we will check again
517 * in CheckInit before nuking the database. Since this may now get
518 * a UNOQUORUM we'll just do this from the top.
520 if ((code
= InitAuthServ(tt
, LOCKWRITE
, this_op
)))
522 if ((code
= ubik_EndTrans(*tt
)))
525 /* now open the read transaction that was originally requested. */
526 return InitAuthServ(tt
, lock
, this_op
);
529 if ((code
= CheckInit(*tt
, rebuildDatabase
))) {
532 ubik_AbortTrans(*tt
);
537 ka_FillKeyCache(*tt
); /* ensure in-core copy is uptodate */
541 /* returns true if name is specially known by AuthServer */
544 special_name(char *name
, char *instance
)
547 return ((!strcmp(name
, KA_TGS_NAME
) && !strcmp(instance
, lrealm
))
548 || (strcmp(name
, KA_ADMIN_NAME
) == 0));
552 create_user(struct ubik_trans
*tt
, char *name
, char *instance
,
553 struct ktc_encryptionKey
*key
, afs_int32 caller
,
558 struct kaentry tentry
;
559 afs_int32 maxLifetime
;
561 code
= FindBlock(tt
, name
, instance
, &to
, &tentry
);
565 return KAEXIST
; /* name already exists, we fail */
567 to
= AllocBlock(tt
, &tentry
);
571 /* otherwise we have a block */
572 strncpy(tentry
.userID
.name
, name
, sizeof(tentry
.userID
.name
));
573 strncpy(tentry
.userID
.instance
, instance
, sizeof(tentry
.userID
.instance
));
574 tentry
.flags
= htonl(flags
);
575 if (special_name(name
, instance
)) { /* this overrides key & version */
576 tentry
.flags
= htonl(ntohl(tentry
.flags
) | KAFSPECIAL
);
577 tentry
.key_version
= htonl(-1); /* don't save this key */
578 if ((code
= ka_NewKey(tt
, to
, &tentry
, key
)))
581 memcpy(&tentry
.key
, key
, sizeof(tentry
.key
));
582 tentry
.key_version
= htonl(0);
584 tentry
.user_expiration
= htonl(NEVERDATE
);
585 code
= get_time(&tentry
.modification_time
, tt
, 1);
589 /* time and addr of entry for guy changing this entry */
590 tentry
.modification_time
= htonl(tentry
.modification_time
);
591 tentry
.modification_id
= htonl(caller
);
592 tentry
.change_password_time
= tentry
.modification_time
;
594 if (strcmp(name
, KA_TGS_NAME
) == 0)
595 maxLifetime
= MAXKTCTICKETLIFETIME
;
596 else if (strcmp(name
, KA_ADMIN_NAME
) == 0)
597 maxLifetime
= 10 * 3600;
598 else if (strcmp(name
, AUTH_SUPERUSER
) == 0)
599 maxLifetime
= 100 * 3600;
601 maxLifetime
= 25 * 3600; /* regular users */
602 tentry
.max_ticket_lifetime
= htonl(maxLifetime
);
604 code
= ThreadBlock(tt
, to
, &tentry
);
608 /* Put actual stub routines here */
611 SKAM_CreateUser(struct rx_call
*call
, char *aname
, char *ainstance
,
612 EncryptionKey ainitpw
)
616 code
= kamCreateUser(call
, aname
, ainstance
, ainitpw
);
617 osi_auditU(call
, AFS_KAM_CrUserEvent
, code
, AUD_STR
, aname
, AUD_STR
,
624 kamCreateUser(struct rx_call
*call
, char *aname
, char *ainstance
,
625 EncryptionKey ainitpw
)
628 struct ubik_trans
*tt
;
629 afs_int32 caller
; /* Disk offset of caller's entry */
631 COUNT_REQ(CreateUser
);
632 if (!des_check_key_parity(EncryptionKey_to_cblock(&ainitpw
)) || 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
, call
->conn
->peer
->host
,
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
)) || des_is_weak_key(EncryptionKey_to_cblock(&apassword
)))
897 if (!name_instance_legal(aname
, ainstance
))
899 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
901 code
= check_auth(call
, tt
, 0, &caller
);
905 if ((code
= karead(tt
, caller
, (char *)&tentry
, sizeof(tentry
)))) {
909 /* if the user is changing his own password or ADMIN then go ahead. */
910 if ((strcmp(tentry
.userID
.name
, aname
) == 0)
911 && (strcmp(tentry
.userID
.instance
, ainstance
) == 0)) {
912 if (ntohl(tentry
.flags
) & KAFNOCPW
)
915 code
= impose_reuse_limits(&apassword
, &tentry
);
918 set_password(tt
, aname
, ainstance
, EncryptionKey_to_ktc(&apassword
), akvno
, 0);
920 } else if (ntohl(tentry
.flags
) & KAFADMIN
) {
921 code
= set_password(tt
, aname
, ainstance
, EncryptionKey_to_ktc(&apassword
), akvno
, caller
);
927 code
= ubik_EndTrans(tt
);
928 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
, call
->conn
->peer
->host
,
939 CoerseLifetime(Date start
, Date end
)
941 unsigned char kerberosV4Life
;
942 kerberosV4Life
= time_to_life(start
, end
);
943 end
= life_to_time(start
, kerberosV4Life
);
948 GetEndTime(Date start
, /* start time of ticket */
949 Date reqEnd
, /* requested end time */
950 Date expiration
, /* authorizing ticket's expiration */
951 struct kaentry
*caller
,
952 struct kaentry
*server
,
953 Date
*endP
) /* actual end time */
959 if (ntohl(caller
->flags
) & KAFNOTGS
)
960 return KABADUSER
; /* no new tickets for this user */
961 if (expiration
&& (ntohl(server
->flags
) & KAFNOSEAL
))
962 return KABADSERVER
; /* can't be target of GetTicket req */
964 expiration
= NEVERDATE
;
966 cExp
= ntohl(caller
->user_expiration
);
967 sExp
= ntohl(server
->user_expiration
);
972 cLife
= start
+ ntohl(caller
->max_ticket_lifetime
);
973 sLife
= start
+ ntohl(server
->max_ticket_lifetime
);
975 umin(umin(reqEnd
, expiration
),
976 umin(umin(cLife
, sLife
), umin(cExp
, sExp
)));
977 end
= CoerseLifetime(start
, end
);
983 PrepareTicketAnswer(ka_BBS
*oanswer
, afs_int32 challenge
, char *ticket
,
984 afs_int32 ticketLen
, struct ktc_encryptionKey
*sessionKey
,
985 Date start
, Date end
, struct kaentry
*caller
,
986 struct kaentry
*server
, char *cell
, char *label
)
989 struct ka_ticketAnswer
*answer
;
992 code
= KAANSWERTOOLONG
;
993 if (oanswer
->MaxSeqLen
<
994 sizeof(struct ka_ticketAnswer
) - 5 * MAXKTCNAMELEN
- MAXKTCTICKETLEN
+
998 answer
= (struct ka_ticketAnswer
*)oanswer
->SeqBody
;
999 answer
->challenge
= htonl(challenge
);
1000 memcpy(&answer
->sessionKey
, sessionKey
, sizeof(struct ktc_encryptionKey
));
1001 answer
->startTime
= htonl(start
);
1002 answer
->endTime
= htonl(end
);
1003 answer
->kvno
= server
->key_version
;
1004 answer
->ticketLen
= htonl(ticketLen
);
1007 char *ans
= answer
->name
; /* pointer to variable part */
1008 int rem
; /* space remaining */
1009 int len
; /* macro temp. */
1011 rem
= oanswer
->MaxSeqLen
- (ans
- oanswer
->SeqBody
);
1013 #define putstr(str) len = strlen (str)+1;\
1014 if (rem < len) return code;\
1016 ans += len; rem -= len
1017 putstr(caller
->userID
.name
);
1018 putstr(caller
->userID
.instance
);
1020 putstr(server
->userID
.name
);
1021 putstr(server
->userID
.instance
);
1022 if (rem
< ticketLen
+ KA_LABELSIZE
)
1024 memcpy(ans
, ticket
, ticketLen
);
1027 memcpy(ans
, label
, KA_LABELSIZE
);
1029 memset(ans
, 0, KA_LABELSIZE
);
1030 ans
+= KA_LABELSIZE
;
1031 oanswer
->SeqLen
= (ans
- oanswer
->SeqBody
);
1034 answer
->cksum
= htonl(cksum
);
1035 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1036 if (oanswer
->SeqLen
> oanswer
->MaxSeqLen
)
1041 /* This is used to get a ticket granting ticket or an admininstration ticket.
1042 These two specific, built-in servers are special cases, which require the
1043 client's key as an additional security precaution. The GetTicket operation
1044 is normally disabled for these two principals. */
1047 Authenticate(int version
, struct rx_call
*call
, char *aname
, char *ainstance
,
1048 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1051 struct ubik_trans
*tt
;
1052 afs_int32 to
; /* offset of block */
1054 struct kaentry server
; /* entry for desired server */
1055 struct ka_gettgtRequest request
; /* request after decryption */
1056 int tgt
, adm
; /* type of request */
1057 char *sname
; /* principal of server */
1059 char ticket
[MAXKTCTICKETLEN
]; /* our copy of the ticket */
1061 struct ktc_encryptionKey sessionKey
; /* we have to invent a session key */
1062 char *answer
; /* where answer is to be put */
1063 int answer_len
; /* length of answer packet */
1064 Date answer_time
; /* 1+ request time in network order */
1065 afs_int32 temp
; /* for htonl conversions */
1066 des_key_schedule user_schedule
; /* key schedule for user's key */
1067 afs_int32 tgskvno
; /* key version of service key */
1068 struct ktc_encryptionKey tgskey
; /* service key for encrypting ticket */
1070 afs_uint32 pwexpires
;
1072 COUNT_REQ(Authenticate
);
1073 if (!name_instance_legal(aname
, ainstance
))
1075 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1077 get_time(&now
, 0, 0);
1079 sname
= sinst
= NULL
;
1081 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1085 if (to
== 0) { /* no such user */
1090 /* have to check for locked before verifying the password, otherwise all
1091 * KALOCKED means is "yup, you guessed the password all right, now wait a
1092 * few minutes and we'll let you in"
1095 (to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
],
1096 (afs_uint32
) tentry
.misc_auth_bytes
[LOCKTIME
] << 9)) {
1102 save_principal(authPrincipal
, aname
, ainstance
, 0);
1104 /* decrypt request w/ user password */
1105 if ((code
= des_key_sched(ktc_to_cblock(&tentry
.key
), user_schedule
)))
1106 es_Report("In KAAuthenticate: key_sched returned %d\n", code
);
1107 des_pcbc_encrypt(arequest
->SeqBody
, &request
,
1108 min(arequest
->SeqLen
, sizeof(request
)), user_schedule
,
1109 ktc_to_cblockptr(&tentry
.key
), DECRYPT
);
1111 request
.time
= ntohl(request
.time
); /* reorder date */
1112 tgt
= !strncmp(request
.label
, KA_GETTGT_REQ_LABEL
, sizeof(request
.label
));
1113 adm
= !strncmp(request
.label
, KA_GETADM_REQ_LABEL
, sizeof(request
.label
));
1114 if (!(tgt
|| adm
)) {
1115 kaux_inc(to
, ((unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
]) << 9);
1116 code
= KABADREQUEST
;
1119 kaux_write(to
, 0, 0); /* reset counters */
1122 if (!tentry
.misc_auth_bytes
[EXPIRES
]) {
1123 /* 0 in the database means never, but 0 on the network means today */
1124 /* 255 on the network means "long time, maybe never" */
1127 pwexpires
= tentry
.misc_auth_bytes
[EXPIRES
];
1130 ntohl(tentry
.change_password_time
) + 24 * 60 * 60 * pwexpires
;
1131 if (adm
) { /* provide a little slack for admin ticket */
1132 pwexpires
+= 30 * 24 * 60 * 60; /* 30 days */
1134 if (pwexpires
< now
) {
1138 pwexpires
= (pwexpires
- now
) / (24 * 60 * 60);
1139 if (pwexpires
> 255)
1143 #endif /* EXPIREPW */
1145 if (check_ka_skew(request
.time
, now
, KTC_TIME_UNCERTAINTY
)) {
1147 if (oanswer
->MaxSeqLen
< sizeof(afs_int32
))
1148 code
= KAANSWERTOOLONG
;
1149 else { /* return our time if possible */
1150 oanswer
->SeqLen
= sizeof(afs_int32
);
1151 request
.time
= htonl(now
);
1152 memcpy(oanswer
->SeqBody
, &request
.time
, sizeof(afs_int32
));
1158 sname
= (tgt
? KA_TGS_NAME
: KA_ADMIN_NAME
);
1159 sinst
= (tgt
? lrealm
: KA_ADMIN_INST
);
1160 code
= FindBlock(tt
, sname
, sinst
, &to
, &server
);
1168 tgskvno
= ntohl(server
.key_version
);
1169 memcpy(&tgskey
, &server
.key
, sizeof(tgskey
));
1171 code
= des_random_key(ktc_to_cblock(&sessionKey
));
1177 code
= GetEndTime(start
, end
, 0 /*!GetTicket */ , &tentry
, &server
, &end
);
1182 tkt_MakeTicket(ticket
, &ticketLen
, &tgskey
, aname
, ainstance
, "",
1183 start
, end
, &sessionKey
,
1184 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))), sname
,
1192 ticketLen
+ sizeof(Date
) + sizeof(struct ktc_encryptionKey
) +
1193 2 * sizeof(afs_int32
) + KA_LABELSIZE
;
1194 answer_len
= round_up_to_ebs(answer_len
);
1195 if (answer_len
> oanswer
->MaxSeqLen
) {
1196 code
= KAANSWERTOOLONG
;
1199 oanswer
->SeqLen
= answer_len
;
1200 answer
= oanswer
->SeqBody
;
1201 answer_time
= htonl(request
.time
+ 1);
1202 memcpy(answer
, (char *)&answer_time
, sizeof(Date
));
1203 answer
+= sizeof(Date
);
1204 memcpy(answer
, (char *)&sessionKey
, sizeof(struct ktc_encryptionKey
));
1205 answer
+= sizeof(struct ktc_encryptionKey
);
1206 temp
= htonl(tgskvno
);
1207 memcpy(answer
, (char *)&temp
, sizeof(afs_int32
));
1208 answer
+= sizeof(afs_int32
);
1209 temp
= htonl(ticketLen
);
1210 memcpy(answer
, (char *)&temp
, sizeof(afs_int32
));
1211 answer
+= sizeof(afs_int32
);
1212 memcpy(answer
, ticket
, ticketLen
);
1213 answer
+= ticketLen
;
1214 memcpy(answer
, (tgt
? KA_GETTGT_ANS_LABEL
: KA_GETADM_ANS_LABEL
),
1220 PrepareTicketAnswer(oanswer
, request
.time
+ 1, ticket
, ticketLen
,
1221 &sessionKey
, start
, end
, &tentry
, &server
, "",
1222 (tgt
? KA_GETTGT_ANS_LABEL
:
1223 KA_GETADM_ANS_LABEL
));
1228 && oanswer
->SeqLen
< oanswer
->MaxSeqLen
+ sizeof(afs_int32
)) {
1229 temp
= pwexpires
<< 24; /* move it into the high byte */
1230 pwexpires
= htonl(temp
);
1232 memcpy((char *)oanswer
->SeqBody
+ oanswer
->SeqLen
, &pwexpires
,
1234 oanswer
->SeqLen
+= sizeof(afs_int32
);
1235 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1236 if (oanswer
->SeqLen
> oanswer
->MaxSeqLen
) {
1237 code
= KAANSWERTOOLONG
;
1241 #endif /* EXPIREPW */
1245 code
= KAINTERNALERROR
;
1248 des_pcbc_encrypt(oanswer
->SeqBody
, oanswer
->SeqBody
, oanswer
->SeqLen
,
1249 user_schedule
, ktc_to_cblockptr(&tentry
.key
), ENCRYPT
);
1250 code
= ubik_EndTrans(tt
);
1251 KALOG(aname
, ainstance
, sname
, sinst
, NULL
, call
->conn
->peer
->host
,
1257 ubik_AbortTrans(tt
);
1258 KALOG(aname
, ainstance
, sname
, sinst
, NULL
, call
->conn
->peer
->host
,
1264 SKAA_Authenticate_old(struct rx_call
*call
, char *aname
, char *ainstance
,
1265 Date start
, Date end
, ka_CBS
*arequest
,
1270 IOMGR_Sleep(1); /* discourage use of this mechanism */
1272 Authenticate(0, call
, aname
, ainstance
, start
, end
, arequest
,
1274 osi_auditU(call
, AFS_KAA_AuthOEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1275 ainstance
, AUD_END
);
1281 SKAA_Authenticate(struct rx_call
*call
, char *aname
, char *ainstance
,
1282 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1287 Authenticate(1, call
, aname
, ainstance
, start
, end
, arequest
,
1289 osi_auditU(call
, AFS_KAA_AuthEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1290 ainstance
, AUD_END
);
1296 SKAA_AuthenticateV2(struct rx_call
*call
, char *aname
, char *ainstance
,
1297 Date start
, Date end
, ka_CBS
*arequest
, ka_BBS
*oanswer
)
1302 Authenticate(2, call
, aname
, ainstance
, start
, end
, arequest
,
1304 osi_auditU(call
, AFS_KAA_AuthEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1305 ainstance
, AUD_END
);
1311 SKAM_SetFields(struct rx_call
*call
,
1316 afs_int32 alifetime
,
1317 afs_int32 amaxAssociates
,
1318 afs_uint32 misc_auth_bytes
, /* 4 bytes, each 0 means unspecified */
1324 kamSetFields(call
, aname
, ainstance
, aflags
, aexpiration
, alifetime
,
1325 amaxAssociates
, misc_auth_bytes
, spare2
);
1326 osi_auditU(call
, AFS_KAM_SetFldEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1327 ainstance
, AUD_LONG
, aflags
, AUD_DATE
, aexpiration
, AUD_LONG
,
1328 alifetime
, AUD_LONG
, amaxAssociates
, AUD_END
);
1333 kamSetFields(struct rx_call
*call
,
1338 afs_int32 alifetime
,
1339 afs_int32 amaxAssociates
,
1340 afs_uint32 misc_auth_bytes
, /* 4 bytes, each 0 means unspecified */
1345 struct ubik_trans
*tt
;
1347 afs_int32 tentry_offset
; /* offset of entry */
1348 struct kaentry tentry
;
1349 unsigned char newvals
[4];
1351 COUNT_REQ(SetFields
);
1354 return KABADARGUMENT
; /* not supported yet... */
1356 /* make sure we're supposed to do something */
1357 if (!(aflags
|| aexpiration
|| alifetime
|| (amaxAssociates
>= 0)
1359 || ((aflags
& ~KAFNORMAL
) & ~KAF_SETTABLE_FLAGS
))
1360 return KABADARGUMENT
; /* arguments no good */
1361 if (!name_instance_legal(aname
, ainstance
))
1363 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
1365 code
= check_auth(call
, tt
, 1, &caller
);
1370 code
= FindBlock(tt
, aname
, ainstance
, &tentry_offset
, &tentry
);
1373 if (tentry_offset
== 0) { /* no such user */
1377 if ((ntohl(tentry
.flags
) & KAFNORMAL
) == 0)
1378 return KAINTERNALERROR
;
1380 /* Keep track of the total number of admin accounts. This way we can
1381 * update database without any admin privilege initially */
1382 if ((aflags
& KAFADMIN
) != (ntohl(tentry
.flags
) & KAFADMIN
)) {
1383 /* if admin state is changing */
1385 if (ntohl(tentry
.flags
) & KAFADMIN
)
1389 if ((code
= update_admin_count(tt
, delta
)))
1393 htonl((ntohl(tentry
.flags
) & ~KAF_SETTABLE_FLAGS
) | aflags
);
1395 if ((code
= get_time(&now
, tt
, 1)))
1398 tentry
.user_expiration
= htonl(aexpiration
);
1399 if (!ntohl(tentry
.change_password_time
)) {
1400 tentry
.change_password_time
= htonl(now
);
1404 tentry
.max_ticket_lifetime
= htonl(alifetime
);
1406 #ifndef NOPWCONTROLS
1408 * We've packed a bunch of bytes into a long for backward compatibility.
1409 * These include password expiration time, and some failed login limits
1410 * counters. Now let's unpack them and stick them into the
1411 * kaentry struct. All the bytes have values in the range
1412 * 1..255, else they were not specified in the interface, and are
1414 * In the case of password expiration times, 1 means password never
1415 * expires (==>0), 2 means password only lives for one day (==>1),
1418 if (misc_auth_bytes
) {
1419 unpack_long(misc_auth_bytes
, newvals
);
1420 if (newvals
[EXPIRES
]) {
1421 tentry
.misc_auth_bytes
[EXPIRES
] = newvals
[EXPIRES
] - 1;
1424 if (newvals
[REUSEFLAGS
]) {
1425 if (newvals
[REUSEFLAGS
] & KA_REUSEPW
)
1426 memset(tentry
.pwsums
, 0, KA_NPWSUMS
);
1427 else if ((newvals
[REUSEFLAGS
] & KA_NOREUSEPW
)
1428 && !tentry
.pwsums
[0])
1429 tentry
.pwsums
[0] = 0xff;
1432 if (newvals
[ATTEMPTS
]) {
1433 tentry
.misc_auth_bytes
[ATTEMPTS
] = newvals
[ATTEMPTS
] - 1;
1435 if (newvals
[LOCKTIME
]) {
1436 tentry
.misc_auth_bytes
[LOCKTIME
] = newvals
[LOCKTIME
] - 1;
1439 tentry.misc_auth_bytes = htonl(tentry.misc_auth_bytes);
1442 #endif /* NOPWCONTROLS */
1444 if (amaxAssociates
>= 0) {
1445 if ((ntohl(tentry
.flags
) & KAFASSOC
)
1446 || (ntohl(tentry
.flags
) & KAFSPECIAL
))
1448 if (((ntohl(tentry
.flags
) & KAFASSOCROOT
) == 0) && (amaxAssociates
> 0)) /* convert normal user to assoc root */
1449 tentry
.flags
= htonl(ntohl(tentry
.flags
) | KAFASSOCROOT
);
1450 tentry
.misc
.assocRoot
.maxAssociates
= htonl(amaxAssociates
);
1453 tentry
.modification_time
= htonl(now
);
1454 tentry
.modification_id
= htonl(caller
);
1455 code
= kawrite(tt
, tentry_offset
, (char *) &tentry
, sizeof(tentry
));
1459 code
= ubik_EndTrans(tt
);
1460 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
, call
->conn
->peer
->host
,
1466 ubik_AbortTrans(tt
);
1473 SKAM_DeleteUser(struct rx_call
*call
, char *aname
, char *ainstance
)
1477 code
= kamDeleteUser(call
, aname
, ainstance
);
1478 osi_auditU(call
, AFS_KAM_DelUserEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1479 ainstance
, AUD_END
);
1484 kamDeleteUser(struct rx_call
*call
, char *aname
, char *ainstance
)
1487 struct ubik_trans
*tt
;
1490 struct kaentry tentry
;
1491 unsigned int nfailures
;
1492 afs_uint32 locktime
;
1494 COUNT_REQ(DeleteUser
);
1495 if (!name_instance_legal(aname
, ainstance
))
1497 if ((code
= InitAuthServ(&tt
, LOCKWRITE
, this_op
)))
1499 code
= check_auth(call
, tt
, 1, &caller
);
1503 ubik_AbortTrans(tt
);
1507 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1510 if (to
== 0) { /* name not found */
1515 kaux_read(to
, &nfailures
, &locktime
);
1516 if (nfailures
|| locktime
)
1517 kaux_write(to
, 0, 0); /* zero failure counters at this offset */
1519 /* track all AuthServer identities */
1520 if (special_name(aname
, ainstance
))
1521 if ((code
= ka_DelKey(tt
, to
, &tentry
)))
1524 if (ntohl(tentry
.flags
) & KAFADMIN
) /* keep admin count up-to-date */
1525 if ((code
= update_admin_count(tt
, -1)))
1528 if ((code
= UnthreadBlock(tt
, &tentry
)) || (code
= FreeBlock(tt
, to
)) || (code
= get_time(0, tt
, 1)) /* update randomness */
1532 code
= ubik_EndTrans(tt
);
1533 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
, call
->conn
->peer
->host
,
1538 /* we set a bit in here which indicates that the user's limit of
1539 * authentication failures has been exceeded. If that bit is not set,
1540 * kas can take it on faith that the user ID is not locked. If that
1541 * bit is set, kas has to check all the servers to find one who will
1542 * report that the ID is not locked, or else to find out when the ID
1546 SKAM_GetEntry(struct rx_call
*call
,
1549 afs_int32 aversion
, /* major version assumed by caller */
1550 kaentryinfo
*aentry
) /* entry data copied here */
1554 code
= kamGetEntry(call
, aname
, ainstance
, aversion
, aentry
);
1555 osi_auditU(call
, AFS_KAM_GetEntEvent
, code
, AUD_STR
, aname
, AUD_STR
,
1556 ainstance
, AUD_END
);
1561 kamGetEntry(struct rx_call
*call
,
1564 afs_int32 aversion
, /* major version assumed by caller */
1565 kaentryinfo
*aentry
) /* entry data copied here */
1568 struct ubik_trans
*tt
;
1569 afs_int32 callerIndex
;
1570 struct kaentry caller
;
1573 struct kaentry tentry
;
1574 rxkad_level enc_level
= rxkad_clear
;
1575 int callerIsAdmin
= 0;
1577 COUNT_REQ(GetEntry
);
1578 if (aversion
!= KAMAJORVERSION
)
1579 return KAOLDINTERFACE
;
1580 if (!name_instance_legal(aname
, ainstance
))
1582 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1584 code
= check_auth(call
, tt
, 0, &callerIndex
);
1588 if (noAuthenticationRequired
) {
1589 } else if (!callerIndex
) {
1593 if ((code
= karead(tt
, callerIndex
, (char *)&caller
, sizeof(caller
)))) {
1597 /* if the user is checking his own entry or ADMIN then go ahead. */
1598 callerIsAdmin
= (ntohl(caller
.flags
) & KAFADMIN
);
1600 if (strcmp(caller
.userID
.name
, aname
) != 0 && !callerIsAdmin
) {
1606 code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
);
1609 if (to
== 0) { /* entry not found */
1614 get_time(0, 0, 0); /* generate random update */
1616 memset(aentry
, 0, sizeof(*aentry
));
1617 aentry
->minor_version
= KAMINORVERSION
;
1618 aentry
->flags
= ntohl(tentry
.flags
);
1619 aentry
->user_expiration
= ntohl(tentry
.user_expiration
);
1620 aentry
->modification_time
= ntohl(tentry
.modification_time
);
1621 aentry
->change_password_time
= ntohl(tentry
.change_password_time
);
1622 aentry
->max_ticket_lifetime
= ntohl(tentry
.max_ticket_lifetime
);
1623 aentry
->key_version
= ntohl(tentry
.key_version
);
1625 temp
= (unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
];
1627 if (kaux_islocked(to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
], temp
))
1628 tentry
.misc_auth_bytes
[REUSEFLAGS
] |= KA_ISLOCKED
; /* saves an RPC */
1630 temp
= pack_long(tentry
.misc_auth_bytes
);
1631 aentry
->misc_auth_bytes
= temp
;
1633 * only return user's key if security disabled or if admin and
1634 * we have an encrypted connection to the user
1636 rxkad_GetServerInfo(call
->conn
, &enc_level
, 0, 0, 0, 0, 0);
1637 if ((noAuthenticationRequired
)
1638 || (callerIsAdmin
&& enc_level
== rxkad_crypt
))
1639 memcpy(&aentry
->key
, &tentry
.key
, sizeof(struct ktc_encryptionKey
));
1641 memset(&aentry
->key
, 0, sizeof(aentry
->key
));
1642 code
= ka_KeyCheckSum((char *)&tentry
.key
, &aentry
->keyCheckSum
);
1643 if (!tentry
.pwsums
[0] && npwSums
> 1 && !tentry
.pwsums
[1]) {
1644 aentry
->reserved3
= 0x12340000;
1646 aentry
->reserved3
= 0x12340001;
1649 /* Now get entry of user who last modified this entry */
1650 if (ntohl(tentry
.modification_id
)) {
1651 temp
= ntohl(tentry
.modification_id
);
1652 code
= karead(tt
, temp
, (char *)&tentry
, sizeof(tentry
));
1657 aentry
->modification_user
= tentry
.userID
;
1659 strcpy(aentry
->modification_user
.name
, "<none>");
1660 strcpy(aentry
->modification_user
.instance
, "\0");
1662 code
= ubik_EndTrans(tt
);
1667 ubik_AbortTrans(tt
);
1672 SKAM_ListEntry(struct rx_call
*call
,
1673 afs_int32 previous_index
, /* last entry ret'd or 0 for first */
1674 afs_int32
*index
, /* index of this entry */
1675 afs_int32
*count
, /* total entries in database */
1676 kaident
*name
) /* name & instance of this entry */
1680 code
= kamListEntry(call
, previous_index
, index
, count
, name
);
1681 osi_auditU(call
, AFS_KAM_LstEntEvent
, code
, AUD_LONG
, *index
, AUD_END
);
1687 kamListEntry(struct rx_call
*call
,
1688 afs_int32 previous_index
, /* last entry ret'd or 0 for first */
1689 afs_int32
*index
, /* index of this entry */
1690 afs_int32
*count
, /* total entries in database */
1691 kaident
*name
) /* name & instance of this entry */
1694 struct ubik_trans
*tt
;
1696 struct kaentry tentry
;
1698 COUNT_REQ(ListEntry
);
1699 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1701 code
= check_auth(call
, tt
, 1, &caller
);
1706 *index
= NextBlock(tt
, previous_index
, &tentry
, count
);
1712 if (*index
) { /* return name & inst of this entry */
1713 strncpy(name
->name
, tentry
.userID
.name
, sizeof(name
->name
));
1714 strncpy(name
->instance
, tentry
.userID
.instance
,
1715 sizeof(name
->instance
));
1717 strcpy(name
->name
, "\0");
1718 strcpy(name
->instance
, "\0");
1720 code
= ubik_EndTrans(tt
);
1725 ubik_AbortTrans(tt
);
1730 GetTicket(int version
,
1731 struct rx_call
*call
,
1737 ka_CBS
*atimes
, /* encrypted start & end time */
1742 struct ubik_trans
*tt
;
1743 struct ktc_encryptionKey tgskey
;
1744 des_key_schedule schedule
;
1746 char name
[MAXKTCNAMELEN
];
1747 char instance
[MAXKTCNAMELEN
];
1748 char cell
[MAXKTCNAMELEN
];
1750 struct kaentry caller
;
1751 struct kaentry server
;
1752 struct ktc_encryptionKey authSessionKey
;
1753 struct ktc_encryptionKey sessionKey
;
1755 char ticket
[MAXKTCTICKETLEN
];
1761 struct ka_getTicketTimes times
;
1762 struct ka_getTicketAnswer
*answer
;
1764 COUNT_REQ(GetTicket
);
1765 if (!name_instance_legal(sname
, sinstance
))
1767 if (atimes
->SeqLen
!= sizeof(times
))
1768 return KABADARGUMENT
;
1769 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
1772 export
= import
= 0;
1773 if ((strcmp(sname
, KA_TGS_NAME
) == 0) && (strcmp(sinstance
, lrealm
) != 0))
1775 if ((strlen(authDomain
) > 0) && (strcmp(authDomain
, lrealm
) != 0))
1778 if (strlen(authDomain
) == 0)
1779 authDomain
= lrealm
;
1780 code
= ka_LookupKvno(tt
, KA_TGS_NAME
, authDomain
, kvno
, &tgskey
);
1785 tkt_DecodeTicket(aticket
->SeqBody
, aticket
->SeqLen
, &tgskey
, name
,
1786 instance
, cell
, &authSessionKey
, &host
, &start
,
1792 save_principal(tgsPrincipal
, name
, instance
, cell
);
1794 if ((code
= get_time(&now
, 0, 0)))
1797 code
= tkt_CheckTimes(start
, expiration
, now
);
1800 code
= RXKADEXPIRED
;
1805 code
= des_key_sched(ktc_to_cblock(&authSessionKey
), schedule
);
1810 celllen
= strlen(cell
);
1811 if (import
&& (celllen
== 0)) {
1815 if (export
&& (celllen
== 0))
1816 strcpy(cell
, lrealm
);
1818 if (!krb4_cross
&& celllen
&& strcmp(lrealm
, cell
) != 0) {
1823 des_ecb_encrypt(atimes
->SeqBody
, ×
, schedule
, DECRYPT
);
1824 times
.start
= ntohl(times
.start
);
1825 times
.end
= ntohl(times
.end
);
1826 code
= tkt_CheckTimes(times
.start
, times
.end
, now
);
1828 code
= KABADREQUEST
;
1833 strcpy(caller
.userID
.name
, name
);
1834 strcpy(caller
.userID
.instance
, instance
);
1835 caller
.max_ticket_lifetime
= htonl(MAXKTCTICKETLIFETIME
);
1836 caller
.flags
= htonl(KAFNORMAL
);
1837 caller
.user_expiration
= htonl(NEVERDATE
);
1839 code
= FindBlock(tt
, name
, instance
, &to
, &caller
);
1843 ka_PrintUserID("GetTicket: User ", name
, instance
, " unknown.\n");
1849 /* get server's entry */
1850 code
= FindBlock(tt
, sname
, sinstance
, &to
, &server
);
1853 if (to
== 0) { /* entry not found */
1854 ka_PrintUserID("GetTicket: Server ", sname
, sinstance
, " unknown.\n");
1858 save_principal(tgsServerPrincipal
, sname
, sinstance
, 0);
1860 code
= des_random_key(ktc_to_cblock(&sessionKey
));
1867 GetEndTime(times
.start
, times
.end
, expiration
, &caller
, &server
,
1873 tkt_MakeTicket(ticket
, &ticketLen
, &server
.key
, caller
.userID
.name
,
1874 caller
.userID
.instance
, cell
, times
.start
, end
,
1876 rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))),
1877 server
.userID
.name
, server
.userID
.instance
);
1883 code
= KAANSWERTOOLONG
;
1884 if (oanswer
->MaxSeqLen
<
1885 sizeof(struct ka_getTicketAnswer
) - 5 * MAXKTCNAMELEN
-
1886 MAXKTCTICKETLEN
+ ticketLen
)
1889 answer
= (struct ka_getTicketAnswer
*)oanswer
->SeqBody
;
1890 memcpy(&answer
->sessionKey
, &sessionKey
,
1891 sizeof(struct ktc_encryptionKey
));
1892 answer
->startTime
= htonl(times
.start
);
1893 answer
->endTime
= htonl(end
);
1894 answer
->kvno
= server
.key_version
;
1895 answer
->ticketLen
= htonl(ticketLen
);
1898 char *ans
= answer
->name
; /* ptr to variable part of answer */
1901 /* space remaining */
1902 rem
= oanswer
->MaxSeqLen
- (ans
- oanswer
->SeqBody
);
1904 #define putstr(str) len = strlen (str)+1;\
1905 if (rem < len) goto abort;\
1907 ans += len; rem -= len
1914 if (rem
< ticketLen
)
1916 memcpy(ans
, ticket
, ticketLen
);
1917 oanswer
->SeqLen
= (ans
- oanswer
->SeqBody
) + ticketLen
;
1919 oanswer
->SeqLen
= round_up_to_ebs(oanswer
->SeqLen
);
1923 PrepareTicketAnswer(oanswer
, /*challenge */ 0, ticket
, ticketLen
,
1924 &sessionKey
, times
.start
, end
, &caller
,
1925 &server
, cell
, KA_GETTICKET_ANS_LABEL
);
1930 code
= KAINTERNALERROR
;
1933 des_pcbc_encrypt(oanswer
->SeqBody
, oanswer
->SeqBody
, oanswer
->SeqLen
,
1934 schedule
, ktc_to_cblockptr(&authSessionKey
), ENCRYPT
);
1935 code
= ubik_EndTrans(tt
);
1936 KALOG(name
, instance
, sname
, sinstance
, (import
? authDomain
: NULL
),
1937 call
->conn
->peer
->host
, LOG_GETTICKET
);
1942 ubik_AbortTrans(tt
);
1947 SKAT_GetTicket_old(struct rx_call
*call
,
1953 ka_CBS
*atimes
, /* encrypted start & end time */
1958 sleep(1); /* strongly discourage this */
1960 GetTicket(0, call
, kvno
, authDomain
, aticket
, sname
, sinstance
,
1963 osi_auditU(call
, AFS_KAT_GetTicketOEvent
, code
, AUD_STR
, sname
, AUD_STR
,
1964 sinstance
, AUD_END
);
1969 SKAT_GetTicket(struct rx_call
*call
,
1975 ka_CBS
*atimes
, /* encrypted start & end time */
1981 GetTicket(1, call
, kvno
, authDomain
, aticket
, sname
, sinstance
,
1983 osi_auditU(call
, AFS_KAT_GetTicketEvent
, code
, AUD_STR
, sname
, AUD_STR
,
1984 sinstance
, AUD_END
);
1989 SKAM_GetStats(struct rx_call
*call
, afs_int32 version
,
1990 afs_int32
*admin_accounts
, kasstats
*statics
,
1995 code
= kamGetStats(call
, version
, admin_accounts
, statics
, dynamics
);
1996 osi_auditU(call
, AFS_KAM_GetStatEvent
, code
, AUD_END
);
2001 kamGetStats(struct rx_call
*call
, afs_int32 version
,
2002 afs_int32
*admin_accounts
, kasstats
*statics
,
2006 struct ubik_trans
*tt
;
2009 COUNT_REQ(GetStats
);
2010 if (version
!= KAMAJORVERSION
)
2011 return KAOLDINTERFACE
;
2012 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2014 code
= check_auth(call
, tt
, 1, &caller
);
2017 ubik_AbortTrans(tt
);
2021 *admin_accounts
= ntohl(cheader
.admin_accounts
);
2022 /* memcpy((char *)statics, (char *)&cheader.stats, sizeof(kasstats)); */
2023 /* these are stored in network byte order and must be copied */
2024 statics
->allocs
= ntohl(cheader
.stats
.allocs
);
2025 statics
->frees
= ntohl(cheader
.stats
.frees
);
2026 statics
->cpws
= ntohl(cheader
.stats
.cpws
);
2027 #if KADBVERSION != 5
2028 check that the statistics command copies all the fields
2030 memcpy((char *)dynamics
, (char *)&dynamic_statistics
, sizeof(kadstats
));
2031 statics
->minor_version
= KAMINORVERSION
;
2032 dynamics
->minor_version
= KAMINORVERSION
;
2038 for (i
= 0; i
< HASHSIZE
; i
++)
2039 if (cheader
.nameHash
[i
])
2041 dynamics
->hashTableUtilization
=
2042 (used
* 10000 + HASHSIZE
/ 2) / HASHSIZE
;
2045 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_NT40_ENV)
2047 /* Unfortunately, although aix_22 has a minimal compatibility
2048 * method of getting to some rusage fields (i.e. stime &
2049 * utime), the version that we have doesn't even have the
2050 * related include files needed for the aix vtimes() call; so
2051 * ignore this for aix till v3.1... */
2052 getrusage(RUSAGE_SELF
, &ru
);
2053 #if (KAMAJORVERSION>5)
2054 memcpy(&dynamics
->utime
, &ru
.ru_utime
, sizeof(struct katimeval
));
2055 memcpy(&dynamics
->stime
, &ru
.ru_stime
, sizeof(struct katimeval
));
2056 dynamics
->dataSize
= ru
.ru_idrss
;
2057 dynamics
->stackSize
= ru
.ru_isrss
;
2058 dynamics
->pageFailts
= ru
.ru_majflt
;
2060 dynamics
->string_checks
=
2061 (afs_int32
) (1000.0 *
2062 ((ru
.ru_utime
.tv_sec
+
2063 ru
.ru_utime
.tv_usec
/ 1000000.0) +
2064 (ru
.ru_stime
.tv_sec
+
2065 ru
.ru_stime
.tv_usec
/ 1000000.0)));
2067 #endif /* AFS_AIX_ENV && AFS_HPUX_ENV && AFS_NT40_ENV */
2070 code
= ubik_EndTrans(tt
);
2075 SKAM_GetPassword(struct rx_call
*call
, char *name
, EncryptionKey
*password
)
2079 code
= kamGetPassword(call
, name
, password
);
2080 osi_auditU(call
, AFS_KAM_GetPswdEvent
, code
, AUD_STR
, name
, AUD_END
);
2085 kamGetPassword(struct rx_call
*call
, char *name
, EncryptionKey
*password
)
2087 int code
= KANOAUTH
;
2088 AFS_UNUSED
COUNT_REQ(GetPassword
);
2092 struct ubik_trans
*tt
;
2093 struct kaentry tentry
;
2095 if (!name_instance_legal(name
, ""))
2097 /* only requests from this host work */
2098 if (rx_HostOf(rx_PeerOf(rx_ConnectionOf(call
))) !=
2099 htonl(INADDR_LOOPBACK
))
2101 if (code
= InitAuthServ(&tt
, LOCKREAD
, this_op
))
2104 /* this isn't likely to be used because of string to key problems, so since
2105 * this is a temporary thing anyway, we'll use it here. */
2107 extern char udpAuthPrincipal
[256];
2109 save_principal(udpAuthPrincipal
, name
, 0, 0);
2112 get_time(0, 0, 0); /* update random value */
2113 code
= FindBlock(tt
, name
, "", &to
, &tentry
);
2120 ubik_AbortTrans(tt
);
2124 memcpy(password
, &tentry
.key
, sizeof(*password
));
2125 code
= ubik_EndTrans(tt
);
2132 SKAM_GetRandomKey(struct rx_call
*call
, EncryptionKey
*key
)
2136 code
= kamGetRandomKey(call
, key
);
2137 osi_auditU(call
, AFS_KAM_GetRndKeyEvent
, code
, AUD_END
);
2142 kamGetRandomKey(struct rx_call
*call
, EncryptionKey
*key
)
2146 AFS_UNUSED
COUNT_REQ(GetRandomKey
);
2147 if ((code
= AwaitInitialization()))
2149 code
= des_random_key(EncryptionKey_to_cblock(key
));
2156 SKAM_Debug(struct rx_call
*call
,
2158 int checkDB
, /* start a transaction to examine DB */
2159 struct ka_debugInfo
*info
)
2163 code
= kamDebug(call
, version
, checkDB
, info
);
2164 osi_auditU(call
, AFS_KAM_DbgEvent
, code
, AUD_END
);
2169 kamDebug(struct rx_call
*call
,
2171 int checkDB
, /* start a transaction to examine DB */
2172 struct ka_debugInfo
*info
)
2174 /* COUNT_REQ (Debug); */
2175 if (sizeof(struct kaentry
) != sizeof(struct kaOldKeys
))
2176 return KAINTERNALERROR
;
2177 if (sizeof(struct ka_cpwRequest
) % 8)
2178 return KAINTERNALERROR
;
2179 if (version
!= KAMAJORVERSION
)
2180 return KAOLDINTERFACE
;
2182 memset(info
, 0, sizeof(*info
));
2184 info
->minorVersion
= KAMINORVERSION
;
2185 info
->host
= dynamic_statistics
.host
;
2186 info
->startTime
= dynamic_statistics
.start_time
;
2188 #if (KAMAJORVERSION>5)
2194 info
->noAuth
= noAuthenticationRequired
;
2196 info
->dbVersion
= ntohl(cheader
.version
);
2197 info
->dbFreePtr
= ntohl(cheader
.freePtr
);
2198 info
->dbEofPtr
= ntohl(cheader
.eofPtr
);
2199 info
->dbKvnoPtr
= ntohl(cheader
.kvnoPtr
);
2200 info
->dbSpecialKeysVersion
= ntohl(cheader
.specialKeysVersion
);
2202 info
->dbHeaderRead
= cheaderReadTime
;
2203 info
->lastTrans
= lastTrans
;
2205 lastOperation
= "(Not Available)";
2206 strncpy(info
->lastOperation
, lastOperation
, sizeof(info
->lastOperation
));
2207 strncpy(info
->lastAuth
, authPrincipal
, sizeof(info
->lastAuth
));
2208 strncpy(info
->lastTGS
, tgsPrincipal
, sizeof(info
->lastTGS
));
2209 strncpy(info
->lastAdmin
, adminPrincipal
, sizeof(info
->lastAdmin
));
2210 strncpy(info
->lastTGSServer
, tgsServerPrincipal
,
2211 sizeof(info
->lastTGSServer
));
2213 extern char udpAuthPrincipal
[256];
2214 extern char udptgsPrincipal
[256];
2215 extern char udptgsServerPrincipal
[256];
2217 strncpy(info
->lastUAuth
, udpAuthPrincipal
, sizeof(info
->lastUAuth
));
2218 strncpy(info
->lastUTGS
, udptgsPrincipal
, sizeof(info
->lastUTGS
));
2219 strncpy(info
->lastUTGSServer
, udptgsServerPrincipal
,
2220 sizeof(info
->lastUTGSServer
));
2222 info
->nextAutoCPW
= nextAutoCPWTime
;
2223 info
->updatesRemaining
= autoCPWUpdates
- totalUpdates
;
2224 ka_debugKeyCache(info
);
2228 /* these are auxiliary routines. They don't do any Ubik stuff. They use
2229 * a tacked-on-the-side data file.
2230 * prob'ly ought to check the noauth flag.
2232 #define ABORTIF(A) {if((code = A)){goto abort;}}
2234 SKAM_Unlock(struct rx_call
*call
,
2243 struct ubik_trans
*tt
;
2246 struct kaentry tentry
;
2249 if (!name_instance_legal(aname
, ainstance
)) {
2253 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2256 ABORTIF(check_auth(call
, tt
, 1, &caller
));
2257 ABORTIF(FindBlock(tt
, aname
, ainstance
, &to
, &tentry
));
2258 ABORTIF((to
== 0 ? KANOENT
: 0));
2260 kaux_write(to
, 0, 0); /* zero failure counters at this offset */
2262 code
= ubik_EndTrans(tt
);
2263 KALOG(aname
, ainstance
, NULL
, NULL
, NULL
, call
->conn
->peer
->host
,
2269 ubik_AbortTrans(tt
);
2272 osi_auditU(call
, UnlockEvent
, code
, AUD_STR
, aname
, AUD_STR
, ainstance
,
2278 SKAM_LockStatus(struct rx_call
*call
,
2281 afs_int32
*lockeduntil
,
2288 struct ubik_trans
*tt
;
2289 afs_int32 callerIndex
;
2291 struct kaentry caller
;
2292 struct kaentry tentry
;
2295 COUNT_REQ(LockStatus
);
2297 if (!name_instance_legal(aname
, ainstance
)) {
2301 if ((code
= InitAuthServ(&tt
, LOCKREAD
, this_op
)))
2304 if ((code
= check_auth(call
, tt
, 0, &callerIndex
)))
2307 if (!noAuthenticationRequired
&& callerIndex
) {
2308 if (karead(tt
, callerIndex
, (char *)&caller
, sizeof(caller
))) {
2312 /* if the user is checking his own entry or ADMIN then go ahead. */
2313 if ((strcmp(caller
.userID
.name
, aname
) != 0)
2314 && !(ntohl(caller
.flags
) & KAFADMIN
)) {
2320 if ((code
= FindBlock(tt
, aname
, ainstance
, &to
, &tentry
)))
2328 temp
= (unsigned char)tentry
.misc_auth_bytes
[LOCKTIME
];
2331 kaux_islocked(to
, (u_int
) tentry
.misc_auth_bytes
[ATTEMPTS
], temp
);
2333 code
= ubik_EndTrans(tt
);
2338 ubik_AbortTrans(tt
);
2339 osi_auditU(call
, LockStatusEvent
, code
, AUD_STR
, aname
, AUD_STR
,
2340 ainstance
, AUD_END
);