1 /*
2  * h_cwd.c
3  * (C)1998-2011 by Marc Huber <Marc.Huber@web.de>
4  *
5  * $Id: h_cwd.c,v 1.14 2015/03/14 06:11:25 marc Exp marc $
6  *
7  */
8 
9 #include "headers.h"
10 
11 static const char rcsid[] __attribute__ ((used)) = "$Id: h_cwd.c,v 1.14 2015/03/14 06:11:25 marc Exp marc $";
12 
h_cwd(struct context * ctx,char * arg)13 void h_cwd(struct context *ctx, char *arg)
14 {
15     char *t = NULL, *u = NULL;
16     struct stat st;
17     int r = -1;
18 
19     Debug((DEBUG_COMMAND, "+ %s %s\n", __func__, arg));
20 
21     if (arg[0] == '.' && arg[1] == '.' && !arg[2]) {
22 	for (u = ctx->cwd + ctx->cwdlen; u > ctx->cwd + ctx->rootlen && *u != '/'; u--);
23 	if (*u != '/')
24 	    u = NULL;
25     }
26 
27   again:
28 
29     if (u) {
30 	*u = 0;
31 	ctx->cwdlen = (u_int) (u - ctx->cwd);
32 	acl_conf_readme(ctx);
33 	file2control(ctx, "250", ctx->readme);
34 	replyf(ctx, MSG_250_Dir_changed, ctx->cwdlen == ctx->rootlen ? "/" : ctx->cwd + ctx->rootlen);
35     } else if ((t = buildpath(ctx, arg)) && !(r = pickystat(ctx, &st, t)) && S_ISDIR(st.st_mode)) {
36 	if ((st.st_mode & S_IXOTH) || ((st.st_mode & S_IXUSR) && (st.st_uid == ctx->uid)) || ((st.st_mode & S_IXGRP) && check_gids(ctx, st.st_gid))) {
37 	    u_int l = (u_int) strlen(t);
38 
39 	    if (ctx->cwdlen >= sizeof(ctx->cwd)) {
40 		logerr("buffer too small in %s:%d (%s/%s)", __FILE__, __LINE__, ctx->user, t);
41 		reply(ctx, MSG_551_Internal_error);
42 		DebugOut(DEBUG_COMMAND);
43 		return;
44 	    }
45 	    strcpy(ctx->cwd, t);
46 	    ctx->cwdlen = l;
47 	    acl_conf_readme(ctx);
48 	    file2control(ctx, "250", ctx->readme);
49 	    replyf(ctx, MSG_250_Dir_changed, ctx->cwdlen == ctx->rootlen ? "/" : ctx->cwd + ctx->rootlen);
50 	} else
51 	    reply(ctx, MSG_550_Permission_denied);
52     } else {
53 	if (r && (arg[0] == '~') && (arg[1] == '/' || !arg[1])) {
54 	    char *c = alloca(ctx->homelen - ctx->rootlen + strlen(arg) + 3);
55 
56 	    strcpy(c, "/");
57 	    strcat(c, ctx->home + ctx->rootlen);
58 	    strcat(c, "/");
59 	    strcat(c, arg + 1);
60 	    arg = c;
61 	    goto again;
62 	}
63 
64 	reply(ctx, MSG_501_No_such_dir);
65     }
66 
67     DebugOut(DEBUG_COMMAND);
68 }
69 
h_cdup(struct context * ctx,char * arg)70 void h_cdup(struct context *ctx, char *arg __attribute__ ((unused)))
71 {
72     h_cwd(ctx, "..");
73 }
74