10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Copyright (c) 2001 Markus Friedl. All rights reserved. 30Sstevel@tonic-gate * Copyright (c) 2001 Damien Miller. All rights reserved. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 60Sstevel@tonic-gate * modification, are permitted provided that the following conditions 70Sstevel@tonic-gate * are met: 80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 90Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 100Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 110Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 120Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 150Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 160Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 170Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 180Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 190Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 200Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 210Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 220Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 230Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 26*5087Sjp161948 /* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 30*5087Sjp161948 #include "includes.h" 31*5087Sjp161948 32*5087Sjp161948 #include <sys/types.h> 33*5087Sjp161948 #include <sys/stat.h> 34*5087Sjp161948 #include <sys/param.h> 35*5087Sjp161948 36*5087Sjp161948 #include <grp.h> 37*5087Sjp161948 #include <pwd.h> 38*5087Sjp161948 #include <stdio.h> 39*5087Sjp161948 #include <string.h> 40*5087Sjp161948 #include <time.h> 41*5087Sjp161948 #include <stdarg.h> 42*5087Sjp161948 43*5087Sjp161948 #include "xmalloc.h" 440Sstevel@tonic-gate #include "buffer.h" 450Sstevel@tonic-gate #include "bufaux.h" 460Sstevel@tonic-gate #include "log.h" 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include "sftp.h" 490Sstevel@tonic-gate #include "sftp-common.h" 500Sstevel@tonic-gate 510Sstevel@tonic-gate /* Clear contents of attributes structure */ 520Sstevel@tonic-gate void 530Sstevel@tonic-gate attrib_clear(Attrib *a) 540Sstevel@tonic-gate { 550Sstevel@tonic-gate a->flags = 0; 560Sstevel@tonic-gate a->size = 0; 570Sstevel@tonic-gate a->uid = 0; 580Sstevel@tonic-gate a->gid = 0; 590Sstevel@tonic-gate a->perm = 0; 600Sstevel@tonic-gate a->atime = 0; 610Sstevel@tonic-gate a->mtime = 0; 620Sstevel@tonic-gate } 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* Convert from struct stat to filexfer attribs */ 650Sstevel@tonic-gate void 66*5087Sjp161948 stat_to_attrib(const struct stat *st, Attrib *a) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate attrib_clear(a); 690Sstevel@tonic-gate a->flags = 0; 700Sstevel@tonic-gate a->flags |= SSH2_FILEXFER_ATTR_SIZE; 710Sstevel@tonic-gate a->size = st->st_size; 720Sstevel@tonic-gate a->flags |= SSH2_FILEXFER_ATTR_UIDGID; 730Sstevel@tonic-gate a->uid = st->st_uid; 740Sstevel@tonic-gate a->gid = st->st_gid; 750Sstevel@tonic-gate a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; 760Sstevel@tonic-gate a->perm = st->st_mode; 770Sstevel@tonic-gate a->flags |= SSH2_FILEXFER_ATTR_ACMODTIME; 780Sstevel@tonic-gate a->atime = st->st_atime; 790Sstevel@tonic-gate a->mtime = st->st_mtime; 800Sstevel@tonic-gate } 810Sstevel@tonic-gate 820Sstevel@tonic-gate /* Convert from filexfer attribs to struct stat */ 830Sstevel@tonic-gate void 84*5087Sjp161948 attrib_to_stat(const Attrib *a, struct stat *st) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate memset(st, 0, sizeof(*st)); 870Sstevel@tonic-gate 880Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 890Sstevel@tonic-gate st->st_size = a->size; 900Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 910Sstevel@tonic-gate st->st_uid = a->uid; 920Sstevel@tonic-gate st->st_gid = a->gid; 930Sstevel@tonic-gate } 940Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 950Sstevel@tonic-gate st->st_mode = a->perm; 960Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 970Sstevel@tonic-gate st->st_atime = a->atime; 980Sstevel@tonic-gate st->st_mtime = a->mtime; 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate /* Decode attributes in buffer */ 1030Sstevel@tonic-gate Attrib * 1040Sstevel@tonic-gate decode_attrib(Buffer *b) 1050Sstevel@tonic-gate { 1060Sstevel@tonic-gate static Attrib a; 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate attrib_clear(&a); 1090Sstevel@tonic-gate a.flags = buffer_get_int(b); 1100Sstevel@tonic-gate if (a.flags & SSH2_FILEXFER_ATTR_SIZE) 1110Sstevel@tonic-gate a.size = buffer_get_int64(b); 1120Sstevel@tonic-gate if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) { 1130Sstevel@tonic-gate a.uid = buffer_get_int(b); 1140Sstevel@tonic-gate a.gid = buffer_get_int(b); 1150Sstevel@tonic-gate } 1160Sstevel@tonic-gate if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1170Sstevel@tonic-gate a.perm = buffer_get_int(b); 1180Sstevel@tonic-gate if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1190Sstevel@tonic-gate a.atime = buffer_get_int(b); 1200Sstevel@tonic-gate a.mtime = buffer_get_int(b); 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate /* vendor-specific extensions */ 1230Sstevel@tonic-gate if (a.flags & SSH2_FILEXFER_ATTR_EXTENDED) { 1240Sstevel@tonic-gate char *type, *data; 1250Sstevel@tonic-gate int i, count; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate count = buffer_get_int(b); 1280Sstevel@tonic-gate for (i = 0; i < count; i++) { 1290Sstevel@tonic-gate type = buffer_get_string(b, NULL); 1300Sstevel@tonic-gate data = buffer_get_string(b, NULL); 1310Sstevel@tonic-gate debug3("Got file attribute \"%s\"", type); 1320Sstevel@tonic-gate xfree(type); 1330Sstevel@tonic-gate xfree(data); 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate return &a; 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* Encode attributes to buffer */ 1400Sstevel@tonic-gate void 141*5087Sjp161948 encode_attrib(Buffer *b, const Attrib *a) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate buffer_put_int(b, a->flags); 1440Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 1450Sstevel@tonic-gate buffer_put_int64(b, a->size); 1460Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { 1470Sstevel@tonic-gate buffer_put_int(b, a->uid); 1480Sstevel@tonic-gate buffer_put_int(b, a->gid); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 1510Sstevel@tonic-gate buffer_put_int(b, a->perm); 1520Sstevel@tonic-gate if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 1530Sstevel@tonic-gate buffer_put_int(b, a->atime); 1540Sstevel@tonic-gate buffer_put_int(b, a->mtime); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* Convert from SSH2_FX_ status to text error message */ 1590Sstevel@tonic-gate const char * 1600Sstevel@tonic-gate fx2txt(int status) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate switch (status) { 1630Sstevel@tonic-gate case SSH2_FX_OK: 164*5087Sjp161948 return(gettext("No error")); 1650Sstevel@tonic-gate case SSH2_FX_EOF: 166*5087Sjp161948 return(gettext("End of file")); 1670Sstevel@tonic-gate case SSH2_FX_NO_SUCH_FILE: 168*5087Sjp161948 return(gettext("No such file or directory")); 1690Sstevel@tonic-gate case SSH2_FX_PERMISSION_DENIED: 170*5087Sjp161948 return(gettext("Permission denied")); 1710Sstevel@tonic-gate case SSH2_FX_FAILURE: 172*5087Sjp161948 return(gettext("Failure")); 1730Sstevel@tonic-gate case SSH2_FX_BAD_MESSAGE: 174*5087Sjp161948 return(gettext("Bad message")); 1750Sstevel@tonic-gate case SSH2_FX_NO_CONNECTION: 176*5087Sjp161948 return(gettext("No connection")); 1770Sstevel@tonic-gate case SSH2_FX_CONNECTION_LOST: 178*5087Sjp161948 return(gettext("Connection lost")); 1790Sstevel@tonic-gate case SSH2_FX_OP_UNSUPPORTED: 180*5087Sjp161948 return(gettext("Operation unsupported")); 1810Sstevel@tonic-gate default: 182*5087Sjp161948 return(gettext("Unknown status")); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate /* NOTREACHED */ 1850Sstevel@tonic-gate } 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* 1880Sstevel@tonic-gate * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh 1890Sstevel@tonic-gate */ 1900Sstevel@tonic-gate char * 191*5087Sjp161948 ls_file(const char *name, const struct stat *st, int remote) 1920Sstevel@tonic-gate { 1930Sstevel@tonic-gate int ulen, glen, sz = 0; 1940Sstevel@tonic-gate struct passwd *pw; 1950Sstevel@tonic-gate struct group *gr; 1960Sstevel@tonic-gate struct tm *ltime = localtime(&st->st_mtime); 1970Sstevel@tonic-gate char *user, *group; 1980Sstevel@tonic-gate char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1]; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate strmode(st->st_mode, mode); 2010Sstevel@tonic-gate if (!remote && (pw = getpwuid(st->st_uid)) != NULL) { 2020Sstevel@tonic-gate user = pw->pw_name; 2030Sstevel@tonic-gate } else { 2040Sstevel@tonic-gate snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid); 2050Sstevel@tonic-gate user = ubuf; 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate if (!remote && (gr = getgrgid(st->st_gid)) != NULL) { 2080Sstevel@tonic-gate group = gr->gr_name; 2090Sstevel@tonic-gate } else { 2100Sstevel@tonic-gate snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid); 2110Sstevel@tonic-gate group = gbuf; 2120Sstevel@tonic-gate } 2130Sstevel@tonic-gate if (ltime != NULL) { 2140Sstevel@tonic-gate if (time(NULL) - st->st_mtime < (365*24*60*60)/2) 2150Sstevel@tonic-gate sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime); 2160Sstevel@tonic-gate else 2170Sstevel@tonic-gate sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate if (sz == 0) 2200Sstevel@tonic-gate tbuf[0] = '\0'; 2210Sstevel@tonic-gate ulen = MAX(strlen(user), 8); 2220Sstevel@tonic-gate glen = MAX(strlen(group), 8); 223*5087Sjp161948 snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode, 224*5087Sjp161948 (u_int)st->st_nlink, ulen, user, glen, group, 225*5087Sjp161948 (unsigned long long)st->st_size, tbuf, name); 2260Sstevel@tonic-gate return xstrdup(buf); 2270Sstevel@tonic-gate } 228