diff options
Diffstat (limited to 'auth.c')
-rw-r--r-- | auth.c | 135 |
1 files changed, 134 insertions, 1 deletions
@@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); +RCSID("$OpenBSD: auth.c,v 1.22 2001/05/20 17:20:35 markus Exp $"); #ifdef HAVE_LOGIN_H #include <login.h> @@ -32,6 +32,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); #include <shadow.h> #endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */ +#include <libgen.h> + #include "xmalloc.h" #include "match.h" #include "groupaccess.h" @@ -40,6 +42,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); #include "auth.h" #include "auth-options.h" #include "canohost.h" +#include "buffer.h" +#include "bufaux.h" /* import */ extern ServerOptions options; @@ -222,3 +226,132 @@ auth_root_allowed(char *method) log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); return 0; } + + +/* + * Given a template and a passwd structure, build a filename + * by substituting % tokenised options. Currently, %% becomes '%', + * %h becomes the home directory and %u the username. + * + * This returns a buffer allocated by xmalloc. + */ +char * +expand_filename(const char *filename, struct passwd *pw) +{ + Buffer buffer; + char *file; + const char *cp; + + /* + * Build the filename string in the buffer by making the appropriate + * substitutions to the given file name. + */ + buffer_init(&buffer); + for (cp = filename; *cp; cp++) { + if (cp[0] == '%' && cp[1] == '%') { + buffer_append(&buffer, "%", 1); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'h') { + buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir)); + cp++; + continue; + } + if (cp[0] == '%' && cp[1] == 'u') { + buffer_append(&buffer, pw->pw_name, + strlen(pw->pw_name)); + cp++; + continue; + } + buffer_append(&buffer, cp, 1); + } + buffer_append(&buffer, "\0", 1); + + /* + * Ensure that filename starts anchored. If not, be backward + * compatible and prepend the '%h/' + */ + file = xmalloc(MAXPATHLEN); + cp = buffer_ptr(&buffer); + if (*cp != '/') + snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp); + else + strlcpy(file, cp, MAXPATHLEN); + + buffer_free(&buffer); + return file; +} + +char * +authorized_keys_file(struct passwd *pw) +{ + return expand_filename(options.authorized_keys_file, pw); +} + +char * +authorized_keys_file2(struct passwd *pw) +{ + return expand_filename(options.authorized_keys_file2, pw); +} + +/* + * Check a given file for security. This is defined as all components + * of the path to the file must either be owned by either the owner of + * of the file or root and no directories must be world writable. + * + * XXX Should any specific check be done for sym links ? + * + * Takes an open file descriptor, the file name, a uid and and + * error buffer plus max size as arguments. + * + * Returns 0 on success and -1 on failure + */ +int +secure_filename(FILE *f, const char *file, uid_t uid, char *err, size_t errlen) +{ + char buf[MAXPATHLEN]; + char *cp; + struct stat st; + + if (realpath(file, buf) == NULL) { + snprintf(err, errlen, "realpath %s failed: %s", file, + strerror(errno)); + return -1; + } + + /* check the open file to avoid races */ + if (fstat(fileno(f), &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { + snprintf(err, errlen, "bad ownership or modes for file %s", + buf); + return -1; + } + + /* for each component of the canonical path, walking upwards */ + for (;;) { + if ((cp = dirname(buf)) == NULL) { + snprintf(err, errlen, "dirname() failed"); + return -1; + } + strlcpy(buf, cp, sizeof(buf)); + + debug3("secure_filename: checking '%s'", buf); + if (stat(buf, &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { + snprintf(err, errlen, + "bad ownership or modes for directory %s", buf); + return -1; + } + + /* + * dirname should always complete with a "/" path, + * but we can be paranoid and check for "." too + */ + if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) + break; + } + return 0; +} |