1.13.1
by Colin Watson
Import upstream version 4.6p1 |
1 |
/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
2 |
/*
|
3 |
* Copyright (c) 2001 Markus Friedl. All rights reserved.
|
|
4 |
* Copyright (c) 2001 Damien Miller. All rights reserved.
|
|
5 |
*
|
|
6 |
* Redistribution and use in source and binary forms, with or without
|
|
7 |
* modification, are permitted provided that the following conditions
|
|
8 |
* are met:
|
|
9 |
* 1. Redistributions of source code must retain the above copyright
|
|
10 |
* notice, this list of conditions and the following disclaimer.
|
|
11 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
12 |
* notice, this list of conditions and the following disclaimer in the
|
|
13 |
* documentation and/or other materials provided with the distribution.
|
|
14 |
*
|
|
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
16 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
17 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
18 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
19 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
20 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
21 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
22 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
23 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
24 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
25 |
*/
|
|
26 |
||
27 |
#include "includes.h" |
|
1.13.1
by Colin Watson
Import upstream version 4.6p1 |
28 |
|
29 |
#include <sys/types.h> |
|
30 |
#include <sys/stat.h> |
|
31 |
#include <sys/param.h> |
|
32 |
||
33 |
#include <grp.h> |
|
34 |
#include <pwd.h> |
|
35 |
#include <stdio.h> |
|
36 |
#include <string.h> |
|
37 |
#include <time.h> |
|
38 |
#include <stdarg.h> |
|
39 |
||
40 |
#include "xmalloc.h" |
|
1
by Noah Meyerhans
Import upstream version 3.8.1p1 |
41 |
#include "buffer.h" |
42 |
#include "log.h" |
|
43 |
||
44 |
#include "sftp.h" |
|
45 |
#include "sftp-common.h" |
|
46 |
||
47 |
/* Clear contents of attributes structure */
|
|
48 |
void
|
|
49 |
attrib_clear(Attrib *a) |
|
50 |
{
|
|
51 |
a->flags = 0; |
|
52 |
a->size = 0; |
|
53 |
a->uid = 0; |
|
54 |
a->gid = 0; |
|
55 |
a->perm = 0; |
|
56 |
a->atime = 0; |
|
57 |
a->mtime = 0; |
|
58 |
}
|
|
59 |
||
60 |
/* Convert from struct stat to filexfer attribs */
|
|
61 |
void
|
|
62 |
stat_to_attrib(const struct stat *st, Attrib *a) |
|
63 |
{
|
|
64 |
attrib_clear(a); |
|
65 |
a->flags = 0; |
|
66 |
a->flags |= SSH2_FILEXFER_ATTR_SIZE; |
|
67 |
a->size = st->st_size; |
|
68 |
a->flags |= SSH2_FILEXFER_ATTR_UIDGID; |
|
69 |
a->uid = st->st_uid; |
|
70 |
a->gid = st->st_gid; |
|
71 |
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
|
72 |
a->perm = st->st_mode; |
|
73 |
a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME; |
|
74 |
a->atime = st->st_atime; |
|
75 |
a->mtime = st->st_mtime; |
|
76 |
}
|
|
77 |
||
78 |
/* Convert from filexfer attribs to struct stat */
|
|
79 |
void
|
|
80 |
attrib_to_stat(const Attrib *a, struct stat *st) |
|
81 |
{
|
|
82 |
memset(st, 0, sizeof(*st)); |
|
83 |
||
84 |
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) |
|
85 |
st->st_size = a->size; |
|
86 |
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { |
|
87 |
st->st_uid = a->uid; |
|
88 |
st->st_gid = a->gid; |
|
89 |
}
|
|
90 |
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
|
91 |
st->st_mode = a->perm; |
|
92 |
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { |
|
93 |
st->st_atime = a->atime; |
|
94 |
st->st_mtime = a->mtime; |
|
95 |
}
|
|
96 |
}
|
|
97 |
||
98 |
/* Decode attributes in buffer */
|
|
99 |
Attrib * |
|
100 |
decode_attrib(Buffer *b) |
|
101 |
{
|
|
102 |
static Attrib a; |
|
103 |
||
104 |
attrib_clear(&a); |
|
105 |
a.flags = buffer_get_int(b); |
|
106 |
if (a.flags & SSH2_FILEXFER_ATTR_SIZE) |
|
107 |
a.size = buffer_get_int64(b); |
|
108 |
if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { |
|
109 |
a.uid = buffer_get_int(b); |
|
110 |
a.gid = buffer_get_int(b); |
|
111 |
}
|
|
112 |
if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
|
113 |
a.perm = buffer_get_int(b); |
|
114 |
if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { |
|
115 |
a.atime = buffer_get_int(b); |
|
116 |
a.mtime = buffer_get_int(b); |
|
117 |
}
|
|
118 |
/* vendor-specific extensions */
|
|
119 |
if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) { |
|
120 |
char *type, *data; |
|
121 |
int i, count; |
|
122 |
||
123 |
count = buffer_get_int(b); |
|
124 |
for (i = 0; i < count; i++) { |
|
125 |
type = buffer_get_string(b, NULL); |
|
126 |
data = buffer_get_string(b, NULL); |
|
127 |
debug3("Got file attribute \"%s\"", type); |
|
128 |
xfree(type); |
|
129 |
xfree(data); |
|
130 |
}
|
|
131 |
}
|
|
132 |
return &a; |
|
133 |
}
|
|
134 |
||
135 |
/* Encode attributes to buffer */
|
|
136 |
void
|
|
137 |
encode_attrib(Buffer *b, const Attrib *a) |
|
138 |
{
|
|
139 |
buffer_put_int(b, a->flags); |
|
140 |
if (a->flags & SSH2_FILEXFER_ATTR_SIZE) |
|
141 |
buffer_put_int64(b, a->size); |
|
142 |
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { |
|
143 |
buffer_put_int(b, a->uid); |
|
144 |
buffer_put_int(b, a->gid); |
|
145 |
}
|
|
146 |
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
|
147 |
buffer_put_int(b, a->perm); |
|
148 |
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { |
|
149 |
buffer_put_int(b, a->atime); |
|
150 |
buffer_put_int(b, a->mtime); |
|
151 |
}
|
|
152 |
}
|
|
153 |
||
154 |
/* Convert from SSH2_FX_ status to text error message */
|
|
155 |
const char * |
|
156 |
fx2txt(int status) |
|
157 |
{
|
|
158 |
switch (status) { |
|
159 |
case SSH2_FX_OK: |
|
160 |
return("No error"); |
|
161 |
case SSH2_FX_EOF: |
|
162 |
return("End of file"); |
|
163 |
case SSH2_FX_NO_SUCH_FILE: |
|
164 |
return("No such file or directory"); |
|
165 |
case SSH2_FX_PERMISSION_DENIED: |
|
166 |
return("Permission denied"); |
|
167 |
case SSH2_FX_FAILURE: |
|
168 |
return("Failure"); |
|
169 |
case SSH2_FX_BAD_MESSAGE: |
|
170 |
return("Bad message"); |
|
171 |
case SSH2_FX_NO_CONNECTION: |
|
172 |
return("No connection"); |
|
173 |
case SSH2_FX_CONNECTION_LOST: |
|
174 |
return("Connection lost"); |
|
175 |
case SSH2_FX_OP_UNSUPPORTED: |
|
176 |
return("Operation unsupported"); |
|
177 |
default: |
|
178 |
return("Unknown status"); |
|
179 |
}
|
|
180 |
/* NOTREACHED */
|
|
181 |
}
|
|
182 |
||
183 |
/*
|
|
184 |
* drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
|
|
185 |
*/
|
|
186 |
char * |
|
187 |
ls_file(const char *name, const struct stat *st, int remote) |
|
188 |
{
|
|
189 |
int ulen, glen, sz = 0; |
|
190 |
struct passwd *pw; |
|
191 |
struct group *gr; |
|
192 |
struct tm *ltime = localtime(&st->st_mtime); |
|
193 |
char *user, *group; |
|
194 |
char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; |
|
195 |
||
196 |
strmode(st->st_mode, mode); |
|
197 |
if (!remote && (pw = getpwuid(st->st_uid)) != NULL) { |
|
198 |
user = pw->pw_name; |
|
199 |
} else { |
|
200 |
snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); |
|
201 |
user = ubuf; |
|
202 |
}
|
|
203 |
if (!remote && (gr = getgrgid(st->st_gid)) != NULL) { |
|
204 |
group = gr->gr_name; |
|
205 |
} else { |
|
206 |
snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); |
|
207 |
group = gbuf; |
|
208 |
}
|
|
209 |
if (ltime != NULL) { |
|
210 |
if (time(NULL) - st->st_mtime < (365*24*60*60)/2) |
|
211 |
sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); |
|
212 |
else
|
|
213 |
sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); |
|
214 |
}
|
|
215 |
if (sz == 0) |
|
216 |
tbuf[0] = '\0'; |
|
217 |
ulen = MAX(strlen(user), 8); |
|
218 |
glen = MAX(strlen(group), 8); |
|
219 |
snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, |
|
220 |
(u_int)st->st_nlink, ulen, user, glen, group, |
|
221 |
(unsigned long long)st->st_size, tbuf, name); |
|
222 |
return xstrdup(buf); |
|
223 |
}
|