diff options
Diffstat (limited to 'auth.c')
-rw-r--r-- | auth.c | 135 |
1 files changed, 134 insertions, 1 deletions
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); | 26 | RCSID("$OpenBSD: auth.c,v 1.22 2001/05/20 17:20:35 markus Exp $"); |
27 | 27 | ||
28 | #ifdef HAVE_LOGIN_H | 28 | #ifdef HAVE_LOGIN_H |
29 | #include <login.h> | 29 | #include <login.h> |
@@ -32,6 +32,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); | |||
32 | #include <shadow.h> | 32 | #include <shadow.h> |
33 | #endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */ | 33 | #endif /* defined(HAVE_SHADOW_H) && !defined(DISABLE_SHADOW) */ |
34 | 34 | ||
35 | #include <libgen.h> | ||
36 | |||
35 | #include "xmalloc.h" | 37 | #include "xmalloc.h" |
36 | #include "match.h" | 38 | #include "match.h" |
37 | #include "groupaccess.h" | 39 | #include "groupaccess.h" |
@@ -40,6 +42,8 @@ RCSID("$OpenBSD: auth.c,v 1.21 2001/03/19 17:07:23 markus Exp $"); | |||
40 | #include "auth.h" | 42 | #include "auth.h" |
41 | #include "auth-options.h" | 43 | #include "auth-options.h" |
42 | #include "canohost.h" | 44 | #include "canohost.h" |
45 | #include "buffer.h" | ||
46 | #include "bufaux.h" | ||
43 | 47 | ||
44 | /* import */ | 48 | /* import */ |
45 | extern ServerOptions options; | 49 | extern ServerOptions options; |
@@ -222,3 +226,132 @@ auth_root_allowed(char *method) | |||
222 | log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); | 226 | log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); |
223 | return 0; | 227 | return 0; |
224 | } | 228 | } |
229 | |||
230 | |||
231 | /* | ||
232 | * Given a template and a passwd structure, build a filename | ||
233 | * by substituting % tokenised options. Currently, %% becomes '%', | ||
234 | * %h becomes the home directory and %u the username. | ||
235 | * | ||
236 | * This returns a buffer allocated by xmalloc. | ||
237 | */ | ||
238 | char * | ||
239 | expand_filename(const char *filename, struct passwd *pw) | ||
240 | { | ||
241 | Buffer buffer; | ||
242 | char *file; | ||
243 | const char *cp; | ||
244 | |||
245 | /* | ||
246 | * Build the filename string in the buffer by making the appropriate | ||
247 | * substitutions to the given file name. | ||
248 | */ | ||
249 | buffer_init(&buffer); | ||
250 | for (cp = filename; *cp; cp++) { | ||
251 | if (cp[0] == '%' && cp[1] == '%') { | ||
252 | buffer_append(&buffer, "%", 1); | ||
253 | cp++; | ||
254 | continue; | ||
255 | } | ||
256 | if (cp[0] == '%' && cp[1] == 'h') { | ||
257 | buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir)); | ||
258 | cp++; | ||
259 | continue; | ||
260 | } | ||
261 | if (cp[0] == '%' && cp[1] == 'u') { | ||
262 | buffer_append(&buffer, pw->pw_name, | ||
263 | strlen(pw->pw_name)); | ||
264 | cp++; | ||
265 | continue; | ||
266 | } | ||
267 | buffer_append(&buffer, cp, 1); | ||
268 | } | ||
269 | buffer_append(&buffer, "\0", 1); | ||
270 | |||
271 | /* | ||
272 | * Ensure that filename starts anchored. If not, be backward | ||
273 | * compatible and prepend the '%h/' | ||
274 | */ | ||
275 | file = xmalloc(MAXPATHLEN); | ||
276 | cp = buffer_ptr(&buffer); | ||
277 | if (*cp != '/') | ||
278 | snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp); | ||
279 | else | ||
280 | strlcpy(file, cp, MAXPATHLEN); | ||
281 | |||
282 | buffer_free(&buffer); | ||
283 | return file; | ||
284 | } | ||
285 | |||
286 | char * | ||
287 | authorized_keys_file(struct passwd *pw) | ||
288 | { | ||
289 | return expand_filename(options.authorized_keys_file, pw); | ||
290 | } | ||
291 | |||
292 | char * | ||
293 | authorized_keys_file2(struct passwd *pw) | ||
294 | { | ||
295 | return expand_filename(options.authorized_keys_file2, pw); | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * Check a given file for security. This is defined as all components | ||
300 | * of the path to the file must either be owned by either the owner of | ||
301 | * of the file or root and no directories must be world writable. | ||
302 | * | ||
303 | * XXX Should any specific check be done for sym links ? | ||
304 | * | ||
305 | * Takes an open file descriptor, the file name, a uid and and | ||
306 | * error buffer plus max size as arguments. | ||
307 | * | ||
308 | * Returns 0 on success and -1 on failure | ||
309 | */ | ||
310 | int | ||
311 | secure_filename(FILE *f, const char *file, uid_t uid, char *err, size_t errlen) | ||
312 | { | ||
313 | char buf[MAXPATHLEN]; | ||
314 | char *cp; | ||
315 | struct stat st; | ||
316 | |||
317 | if (realpath(file, buf) == NULL) { | ||
318 | snprintf(err, errlen, "realpath %s failed: %s", file, | ||
319 | strerror(errno)); | ||
320 | return -1; | ||
321 | } | ||
322 | |||
323 | /* check the open file to avoid races */ | ||
324 | if (fstat(fileno(f), &st) < 0 || | ||
325 | (st.st_uid != 0 && st.st_uid != uid) || | ||
326 | (st.st_mode & 022) != 0) { | ||
327 | snprintf(err, errlen, "bad ownership or modes for file %s", | ||
328 | buf); | ||
329 | return -1; | ||
330 | } | ||
331 | |||
332 | /* for each component of the canonical path, walking upwards */ | ||
333 | for (;;) { | ||
334 | if ((cp = dirname(buf)) == NULL) { | ||
335 | snprintf(err, errlen, "dirname() failed"); | ||
336 | return -1; | ||
337 | } | ||
338 | strlcpy(buf, cp, sizeof(buf)); | ||
339 | |||
340 | debug3("secure_filename: checking '%s'", buf); | ||
341 | if (stat(buf, &st) < 0 || | ||
342 | (st.st_uid != 0 && st.st_uid != uid) || | ||
343 | (st.st_mode & 022) != 0) { | ||
344 | snprintf(err, errlen, | ||
345 | "bad ownership or modes for directory %s", buf); | ||
346 | return -1; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * dirname should always complete with a "/" path, | ||
351 | * but we can be paranoid and check for "." too | ||
352 | */ | ||
353 | if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) | ||
354 | break; | ||
355 | } | ||
356 | return 0; | ||
357 | } | ||