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