diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2004-08-03 19:43:32 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2004-08-03 19:43:32 +0000 |
commit | 19e801a6d263dd0cde6b95d83ef27d907e82602d (patch) | |
tree | 1ad6a7c7a2a0632386ffcecbef9ae054a91f45c0 | |
parent | 4a4fb3686e6b4f0b805466fae33ed185cda2d8c5 (diff) |
Add support for passing a file descriptor back and forth between
the parent program and the login script. This will be used by login
scripts that need to maintain state, for instance keeping a record
locked during authentication while using separate challenge and
response authentication with S/Key. OK deraadt@ marius@ henning@
-rw-r--r-- | lib/libc/gen/auth_subr.3 | 20 | ||||
-rw-r--r-- | lib/libc/gen/auth_subr.c | 94 |
2 files changed, 96 insertions, 18 deletions
diff --git a/lib/libc/gen/auth_subr.3 b/lib/libc/gen/auth_subr.3 index 280d6257d86..e748c1ac71c 100644 --- a/lib/libc/gen/auth_subr.3 +++ b/lib/libc/gen/auth_subr.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: auth_subr.3,v 1.14 2004/01/10 23:31:32 millert Exp $ +.\" $OpenBSD: auth_subr.3,v 1.15 2004/08/03 19:43:31 millert Exp $ .\" .\" Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved. .\" @@ -242,6 +242,24 @@ on the back channel, the state prior to the call to .Fn auth_call is retained. .Pp +The back channel data may also contain a file descriptor passed back +from the login script. +If this is the case, the login script will first send back the string +.Dq fd +to indidate that a file descriptor will be the next data item. +The file descriptor will be passed back to the next invocation of +the login script with a number specified by the +.Fl v Ar fd +option. +This is used to implement stateful challenge/response schemes that require +a persistent connection during the challenge and response. +The copy of the descriptor in the parent process is closed when the +child is running to prevent deadlock when file locking is used. +The descriptor is also closed by a call to +.Fn auth_close +or +.Fn auth_clean . +.Pp The data read from the back channel is also used by the .Fn auth_getvalue and diff --git a/lib/libc/gen/auth_subr.c b/lib/libc/gen/auth_subr.c index 92fb6706de1..1057faf4d3b 100644 --- a/lib/libc/gen/auth_subr.c +++ b/lib/libc/gen/auth_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth_subr.c,v 1.26 2004/01/23 03:48:42 deraadt Exp $ */ +/* $OpenBSD: auth_subr.c,v 1.27 2004/08/03 19:43:31 millert Exp $ */ /*- * Copyright (c) 1995,1996,1997 Berkeley Software Design, Inc. @@ -92,6 +92,8 @@ struct auth_session_t { char spool[MAXSPOOLSIZE]; /* data returned from login script */ int index; /* how much returned thus far */ + int fd; /* connection to authenticator */ + va_list ap0; /* argument list to auth_call */ va_list ap; /* additional arguments to auth_call */ }; @@ -111,6 +113,7 @@ struct auth_session_t { */ static void _add_rmlist(auth_session_t *, char *); static void _auth_spool(auth_session_t *, int); +static void _recv_fd(auth_session_t *, int); static char *_auth_next_arg(auth_session_t *); /* * Set up a known environment for all authentication scripts. @@ -151,6 +154,7 @@ auth_open(void) if ((as = malloc(sizeof(auth_session_t))) != NULL) { memset(as, 0, sizeof(*as)); as->service = defservice; + as->fd = -1; } return (as); @@ -163,7 +167,6 @@ void auth_clean(auth_session_t *as) { struct rmfiles *rm; - struct authopts *opt; struct authdata *data; as->state = 0; @@ -196,6 +199,11 @@ auth_clean(auth_session_t *as) free(as->pwd); as->pwd = NULL; } + + if (as->fd != -1) { + close(as->fd); + as->fd = -1; + } } /* @@ -772,6 +780,10 @@ auth_call(auth_session_t *as, char *path, ...) if ((argv[argc] = _auth_next_arg(as)) != NULL) ++argc; + if (as->fd != -1) { + argv[argc++] = "-v"; + argv[argc++] = "fd=4"; /* AUTH_FD, see below */ + } for (opt = as->optlist; opt != NULL; opt = opt->next) { if (argc < Nargc - 2) { argv[argc++] = "-v"; @@ -820,19 +832,24 @@ auth_call(auth_session_t *as, char *path, ...) goto fail; case 0: #define COMM_FD 3 - close(pfd[0]); - if (pfd[1] != COMM_FD) { - if (dup2(pfd[1], COMM_FD) < 0) - err(1, "dup of backchannel"); - close(pfd[1]); - } - - closefrom(COMM_FD + 1); +#define AUTH_FD 4 + if (dup2(pfd[1], COMM_FD) < 0) + err(1, "dup of backchannel"); + if (as->fd != -1) { + if (dup2(as->fd, AUTH_FD) < 0) + err(1, "dup of auth fd"); + closefrom(AUTH_FD + 1); + } else + closefrom(COMM_FD + 1); execve(path, argv, auth_environ); syslog(LOG_ERR, "%s: %m", path); err(1, "%s", path); default: close(pfd[1]); + if (as->fd != -1) { + close(as->fd); /* so child has only ref */ + as->fd = -1; + } while ((data = as->data) != NULL) { as->data = data->next; if (data->len > 0) { @@ -940,12 +957,48 @@ fail: } static void +_recv_fd(auth_session_t *as, int fd) +{ + struct msghdr msg; + struct cmsghdr *cmp; + char cmsgbuf[CMSG_LEN(sizeof(int))]; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + if (recvmsg(fd, &msg, 0) < 0) + syslog(LOG_ERR, "recvmsg: %m"); + else if (msg.msg_flags & MSG_TRUNC) + syslog(LOG_ERR, "message truncated"); + else if (msg.msg_flags & MSG_CTRUNC) + syslog(LOG_ERR, "control message truncated"); + else if ((cmp = CMSG_FIRSTHDR(&msg)) == NULL) + syslog(LOG_ERR, "missing control message"); + else { + if (cmp->cmsg_level != SOL_SOCKET) + syslog(LOG_ERR, "unexpected cmsg_level %d", + cmp->cmsg_level); + else if (cmp->cmsg_type != SCM_RIGHTS) + syslog(LOG_ERR, "unexpected cmsg_type %d", + cmp->cmsg_type); + else if (cmp->cmsg_len != sizeof(cmsgbuf)) + syslog(LOG_ERR, "bad cmsg_len %d", + cmp->cmsg_len); + else { + if (as->fd != -1) + close(as->fd); + as->fd = *(int *)CMSG_DATA(cmp); + } + } +} + +static void _auth_spool(auth_session_t *as, int fd) { - int r; - char *b; + ssize_t r; + char *b, *s; - while (as->index < sizeof(as->spool) - 1) { + for (s = as->spool + as->index; as->index < sizeof(as->spool) - 1; ) { r = read(fd, as->spool + as->index, sizeof(as->spool) - as->index); if (r <= 0) { @@ -955,12 +1008,19 @@ _auth_spool(auth_session_t *as, int fd) b = as->spool + as->index; as->index += r; /* - * Go ahead and convert newlines into NULs to allow - * easy scanning of the file. + * Convert newlines into NULs to allow easy scanning of the + * file and receive an fd if there is a BI_FDPASS message. + * XXX - checking for BI_FDPASS here is annoying but + * we need to avoid the read() slurping in control data. */ - while (r-- > 0) - if (*b++ == '\n') + while (r-- > 0) { + if (*b++ == '\n') { b[-1] = '\0'; + if (strcasecmp(s, BI_FDPASS) == 0) + _recv_fd(as, fd); + s = b; + } + } } syslog(LOG_ERR, "Overflowed backchannel spool buffer"); |