Password changing hook in kadmind
John Hascall
john at iastate.edu
Fri May 23 18:50:18 EDT 2003
"Donn Cave" <donn at u.washington.edu> sayeth:
> Quoth John Hascall <john at iastate.edu>:
> (quoting Sam Hartman)
> |> Hi. I understand that there are various patches out there that add a
> |> hook to call some external program during the password changing
> |> process either for password synchronization with non-Kerberos
> |> solutions or for password quality checking.
> |
> | My patch doesn't call a program, it writes a file for each transaction
> | which a separate program can deal with. As I recall there are 4
> | points in the kadmin library you need to hook into (create, modify,
> | delete principal, change password). I didn't include any policy
> | change hooks because we don't make much use of policies yet.
> |
> | I know UMich has done a similar thing.
>
> Same here, we write to disk. Single file, though. We hacked ours in
> 4 places in server_stubs.c, and one in schpw.c.
>
> |> Are any of these patches of sufficient quality that we should look at
> |> taking one of them?
> |
> | You could probably implement it from scratch just as quick.
>
> True. My diff is basically six of
> + if (ret.code == 0)
> + loguwpw(prime_arg, arg->pass);
I did all my changes in src/lib/kadm5/srv/svr_principal.c
here is an example:
ret = kdb_delete_entry(handle, principal);
/* begin ISU Kerberos external sync mods */
if (!ret) {
char *printable_princ = NULL;
char *caller_pr_princ = NULL;
int r;
(void)krb5_unparse_name(handle->context, principal, &printable_princ);
if (printable_princ) {
(void)krb5_unparse_name(handle->context,
handle->current_caller, &caller_pr_princ);
r = kadm5_log_db_event(caller_pr_princ,
"user delete %s\n", printable_princ);
free(printable_princ);
if (r) {
/* XXX: undo KDB? for now we just lump it */
}
}
}
/* end ISU Kerberos external sync mods */
I choose plaintest messages of the form
type operation object [keyword value]...\n
because I use this as a part of a larger system which
syncs users (and soon list/groups/etc) between KRB,
W2K and NDS. YMMV. I also chose to put each transaction
in its own file because that makes the partial completion
problem easier for me to handle.
The logger looks like this:
/* XXX: should come from config file... */
static char kadm5_event_dir[1024] = "/var/athena/krb5kdc/sync/events";
static char magic_principal[1024] = "";
int kadm5_log_db_event (
char * caller,
char * fmt,
...
) {
va_list ap;
char me[64];
char buffer[4096]; /* more than any caller sends, but */
char path[1024]; /* still a lame fixed size buffer */
int fd;
int len;
int seq;
int pid;
int ignore = 0;
/*
* If this is the "other way" syncing us, (e.g., a change
* from W2K), then just stop so we don't loop forever.
*/
if (caller != NULL) {
if (magic_principal[0] == '\0') {
gethostname(me, sizeof(me));
sprintf(magic_principal, "%s/%s@%s",
"s-o-m", me, "IASTATE.EDU"
);
}
ignore = (strcmp(caller, magic_principal) == 0);
free(caller);
}
if (ignore) return KADM5_OK;
/*
* get next sequence number under lock
*/
sprintf(path, "%s/.seq", kadm5_event_dir);
fd = open(path, O_RDWR|O_CREAT, 0600);
if (fd == -1) return errno;
if (flock(fd, LOCK_EX) == -1) {
close(fd);
return errno;
}
if ((len = read(fd, buffer, 16)) > 0) {
buffer[len] = '\0';
sscanf(buffer, "%d", &seq);
} else {
buffer[0] = '\0';
seq = 0;
}
if (lseek(fd, 0L, 0) == -1) {
close(fd);
return errno;
}
sprintf(buffer, "%010d\n", seq + 1);
len = strlen(buffer);
if (write(fd, buffer, len) != len) {
close(fd);
return errno;
}
if (close(fd) == -1) return errno;
/*
* write event in temp file, then atomic rename
*/
sprintf(path, "%s/e-%010d", kadm5_event_dir, seq);
fd = open(path, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, 0400);
if (fd == -1) return errno;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
len = strlen(buffer);
if (write(fd, buffer, strlen(buffer)) != len) {
close(fd);
return errno;
}
close(fd);
sprintf(buffer, "%s/e+%010d", kadm5_event_dir, seq);
if (rename(path, buffer) == -1) return errno;
/*
* signal daemon (if any) that there is work to do
*/
sprintf(path, "%s/.pid", kadm5_event_dir);
fd = open(path, O_RDONLY, 0);
if (fd == -1) return KADM5_OK; /* oh well... */
if ((len = read(fd, buffer, 16)) > 0) {
buffer[len] = '\0';
sscanf(buffer, "%d", &pid);
if (pid) kill(pid, SIGHUP); /* or whatever it wants */
}
close(fd);
return KADM5_OK;
}
More information about the krbdev
mailing list