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