LCOV - code coverage report
Current view: top level - src/client - xattr.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 90 129 69.8 %
Date: 2016-01-31 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../cntr.h"
       6             : #include "../log.h"
       7             : #include "../prepend.h"
       8             : #include "extrameta.h"
       9             : #include "xattr.h"
      10             : 
      11             : #ifdef HAVE_SYS_XATTR_H
      12             : #include <sys/xattr.h>
      13             : #endif
      14             : 
      15             : #ifdef HAVE_SYS_EXTATTR_H
      16             : #include <sys/extattr.h>
      17             : #endif
      18             : #ifdef HAVE_LIBUTIL_H
      19             : #include <libutil.h>
      20             : #endif
      21             : 
      22             : #ifdef HAVE_XATTR
      23             : 
      24             : #if defined(HAVE_DARWIN_OS)
      25             : 
      26             : /*
      27             :  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
      28             :  * listxattr, getxattr and setxattr with an extra options argument
      29             :  * which mimics the l variants of the functions when we specify
      30             :  * XATTR_NOFOLLOW as the options value.
      31             :  */
      32             : #define llistxattr(path, list, size) \
      33             : listxattr((path), (list), (size), XATTR_NOFOLLOW)
      34             : #define lgetxattr(path, name, value, size) \
      35             : getxattr((path), (name), (value), (size), 0, XATTR_NOFOLLOW)
      36             : #define lsetxattr(path, name, value, size, flags) \
      37             : setxattr((path), (name), (value), (size), (flags), XATTR_NOFOLLOW)
      38             : 
      39             : 
      40             : static const char *xattr_acl_skiplist[2] = {
      41             :     "com.apple.system.Security",
      42             :     NULL
      43             : };
      44             : #endif // HAVE_DARWIN_OS
      45             : 
      46             : #if defined(HAVE_LINUX_OS)
      47             : static const char *xattr_acl_skiplist[3] = {
      48             :     "system.posix_acl_access",
      49             :     "system.posix_acl_default",
      50             :     NULL
      51             : };
      52             : #endif // HAVE_LINUX_OS
      53             : 
      54             : #if defined(HAVE_FREEBSD_OS)
      55             : static const char *acl_skiplist[2] = {
      56             :     "system.posix1e.acl_access", NULL
      57             : };
      58             : #endif // HAVE_FREEBSD_OS
      59             : 
      60             : #if defined(HAVE_NETBSD_OS)
      61             : static const char *acl_skiplist[1] = { NULL };
      62             : #endif // HAVE_NETBSD_OS
      63             : 
      64             : #ifndef UTEST
      65             : static
      66             : #endif
      67         118 : char *get_next_xattr_str(struct asfd *asfd, char **data, size_t *l,
      68             :         struct cntr *cntr, ssize_t *s, const char *path)
      69             : {
      70         118 :         char *ret=NULL;
      71             : 
      72         118 :         if((sscanf(*data, "%08X", (unsigned int *)s))!=1)
      73             :         {
      74             :                 logw(asfd, cntr, "sscanf of xattr '%s' %zd failed for %s\n",
      75           0 :                         *data, *l, path);
      76           0 :                 return NULL;
      77             :         }
      78         118 :         *data+=8;
      79         118 :         *l-=8;
      80         118 :         if(!(ret=(char *)malloc_w((*s)+1, __func__)))
      81             :                 return NULL;
      82         118 :         memcpy(ret, *data, *s);
      83         118 :         ret[*s]='\0';
      84             : 
      85         118 :         *data+=*s;
      86         118 :         *l-=*s;
      87             : 
      88         118 :         return ret;
      89             : }
      90             : 
      91             : #if defined(HAVE_SYS_EXTATTR_H)
      92             : static int namespaces[2] = {
      93             :         EXTATTR_NAMESPACE_USER,
      94             :         EXTATTR_NAMESPACE_SYSTEM
      95             : };
      96             : 
      97             : int has_xattr(const char *path)
      98             : {
      99             :         int i=0;
     100             :         for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
     101             :         {
     102             :                 if(extattr_list_link(path, namespaces[i], NULL, 0)>0)
     103             :                         return 1;
     104             :         }
     105             :         return 0;
     106             : }
     107             : 
     108             : #define BSD_BUF_SIZE    1024
     109             : int get_xattr(struct asfd *asfd, const char *path,
     110             :         char **xattrtext, size_t *xlen, struct cntr *cntr)
     111             : {
     112             :         int i=0;
     113             :         ssize_t maxlen=0xFFFFFFFF/2;
     114             : 
     115             :         for(i=0; i<(int)(sizeof(namespaces)/sizeof(int)); i++)
     116             :         {
     117             :                 int j=0;
     118             :                 ssize_t len=0;
     119             :                 int have_acl=0;
     120             :                 char *xattrlist=NULL;
     121             :                 char *cnamespace=NULL;
     122             :                 ssize_t totallen=0;
     123             :                 char *toappend=NULL;
     124             :                 char z[BSD_BUF_SIZE]="";
     125             :                 char cattrname[BSD_BUF_SIZE]="";
     126             :                 if((len=extattr_list_link(path, namespaces[i], NULL, 0))<0)
     127             :                 {
     128             :                         logw(asfd, cntr, "could not extattr_list_link of '%s': %zd\n",
     129             :                                 path, len);
     130             :                         return 0; // carry on
     131             :                 }
     132             :                 if(!len) continue;
     133             :                 if(xattrtext && *xattrtext)
     134             :                 {
     135             :                         // Already have some meta text, which means that some
     136             :                         // ACLs were set.
     137             :                         have_acl++;
     138             :                 }
     139             :                 if(!(xattrlist=(char *)calloc_w(1, len+1, __func__)))
     140             :                         return -1;
     141             :                 if((len=extattr_list_link(path, namespaces[i], xattrlist, len))<=0)
     142             :                 {
     143             :                         logw(asfd, cntr, "could not extattr_list_link '%s': %zd\n",
     144             :                                 path, len);
     145             :                         free_w(&xattrlist);
     146             :                         return 0; // carry on
     147             :                 }
     148             :                 xattrlist[len]='\0';
     149             : 
     150             :                 if(extattr_namespace_to_string(namespaces[i], &cnamespace))
     151             :                 {
     152             :                         logp("Failed to convert %d into namespace on '%s'\n",
     153             :                                  namespaces[i], path);
     154             :                         free_w(&xattrlist);
     155             :                         return 0; // carry on
     156             :                 }
     157             : 
     158             : 
     159             :                 for(j=0; j<(int)len; j+=xattrlist[j]+1)
     160             :                 {
     161             :                         int cnt=0;
     162             :                         char tmp1[9];
     163             :                         char tmp2[9];
     164             :                         size_t newlen=0;
     165             :                         size_t zlen=0;
     166             :                         ssize_t vlen=0;
     167             :                         char *val=NULL;
     168             :                         cnt=xattrlist[j];
     169             :                         if(cnt>((int)sizeof(cattrname)-1))
     170             :                                 cnt=((int)sizeof(cattrname)-1);
     171             :                         strncpy(cattrname, xattrlist+(j+1), cnt);
     172             :                         cattrname[cnt]='\0';
     173             :                         snprintf(z, sizeof(z), "%s.%s",
     174             :                                 cnamespace, cattrname);
     175             : 
     176             :                         if(have_acl)
     177             :                         {
     178             :                                 int c=0;
     179             :                                 int skip=0;
     180             :                                 // skip xattr entries that were already saved
     181             :                                 // as ACLs.
     182             :                                 for(c=0; acl_skiplist[c]; c++)
     183             :                                 {
     184             :                                         if(!strcmp(z, acl_skiplist[c]))
     185             :                                         {
     186             :                                                 skip++;
     187             :                                                 break;
     188             :                                         }
     189             :                                 }
     190             :                                 if(skip) continue;
     191             :                         }
     192             :                         zlen=strlen(z);
     193             :                         //printf("\ngot: %s (%s)\n", z, path);
     194             : 
     195             :                         if((vlen=extattr_list_link(path, namespaces[i],
     196             :                                 xattrlist, len))<0)
     197             :                         {
     198             :                                 logw(asfd, cntr, "could not extattr_list_link on %s for %s: %zd\n", path, cnamespace, vlen);
     199             :                                 continue;
     200             :                         }
     201             :                         if(vlen)
     202             :                         {
     203             :                                 if(!(val=(char *)malloc_w(vlen+1, __func__)))
     204             :                                 {
     205             :                                         free_w(&xattrlist);
     206             :                                         free_w(&toappend);
     207             :                                         return -1;
     208             :                                 }
     209             :                                 if((vlen=extattr_get_link(path, namespaces[i],
     210             :                                         cattrname, val, vlen))<0)
     211             :                                 {
     212             :                                         logw(asfd, cntr, "could not extattr_list_link %s for %s: %zd\n", path, cnamespace, vlen);
     213             :                                         free_w(&val);
     214             :                                         continue;
     215             :                                 }
     216             :                                 val[vlen]='\0';
     217             : 
     218             :                                 if(vlen>maxlen)
     219             :                                 {
     220             :                                         logw(asfd, cntr, "xattr value of '%s' too long: %zd\n",
     221             :                                                 path, vlen);
     222             :                                         free_w(&toappend);
     223             :                                         free_w(&val);
     224             :                                         break;
     225             :                                 }
     226             :                         }
     227             : 
     228             :                         snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen);
     229             :                         snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen);
     230             :                         newlen=totallen+8+zlen+8+vlen;
     231             :                         if(!(toappend=(char *)realloc_w(toappend, newlen, __func__)))
     232             :                         {
     233             :                                 free_w(&val);
     234             :                                 free_w(&xattrlist);
     235             :                                 return -1;
     236             :                         }
     237             :                         memcpy(toappend+totallen, tmp1, 8);
     238             :                         totallen+=8;
     239             :                         memcpy(toappend+totallen, z, zlen);
     240             :                         totallen+=zlen;
     241             :                         memcpy(toappend+totallen, tmp2, 8);
     242             :                         totallen+=8;
     243             :                         memcpy(toappend+totallen, val, vlen);
     244             :                         totallen+=vlen;
     245             :                         free_w(&val);
     246             : 
     247             :                         if(totallen>maxlen)
     248             :                         {
     249             :                                 logw(asfd, cntr,
     250             :                                   "xattr length of '%s' grew too long: %lu\n",
     251             :                                   path, (unsigned long)totallen);
     252             :                                 free_w(&val);
     253             :                                 free_w(&toappend);
     254             :                                 free_w(&xattrlist);
     255             :                                 return 0; // carry on
     256             :                         }
     257             :                 }
     258             : 
     259             :                 if(toappend)
     260             :                 {
     261             :                         char tmp3[10];
     262             :                         size_t newlen=0;
     263             :                         snprintf(tmp3, sizeof(tmp3), "%c%08X",
     264             :                                 META_XATTR_BSD, (unsigned int)totallen);
     265             :                         newlen=(*xlen)+9+totallen;
     266             :                         if(!(*xattrtext=(char *)
     267             :                                 realloc_w(*xattrtext, newlen, __func__)))
     268             :                         {
     269             :                                 free_w(&toappend);
     270             :                                 free_w(&xattrlist);
     271             :                                 return -1;
     272             :                         }
     273             :                         memcpy(*xattrtext, tmp3, 9);
     274             :                         (*xlen)+=9;
     275             :                         memcpy((*xattrtext)+(*xlen), toappend, totallen);
     276             :                         (*xlen)+=totallen;
     277             :                         free_w(&toappend);
     278             :                 }
     279             :                 free_w(&xattrlist);
     280             :         }
     281             : 
     282             :         return 0;
     283             : }
     284             : 
     285             : static int do_set_xattr_bsd(struct asfd *asfd,
     286             :         const char *path,
     287             :         const char *xattrtext, size_t xlen, struct cntr *cntr)
     288             : {
     289             :         int ret=-1;
     290             :         size_t l=0;
     291             :         char *data=NULL;
     292             :         char *value=NULL;
     293             :         char *nspace=NULL;
     294             : 
     295             :         data=(char *)xattrtext;
     296             :         l=xlen;
     297             :         while(l>0)
     298             :         {
     299             :                 ssize_t cnt;
     300             :                 ssize_t vlen=0;
     301             :                 int cnspace=0;
     302             :                 char *name=NULL;
     303             : 
     304             :                 if(!(nspace=get_next_xattr_str(asfd, &data, &l,
     305             :                         cntr, &vlen, path))
     306             :                   || !(value=get_next_xattr_str(asfd, &data, &l,
     307             :                         cntr, &vlen, path)))
     308             :                                 goto end;
     309             : 
     310             :                 // Need to split the name into two parts.
     311             :                 if(!(name=strchr(nspace, '.')))
     312             :                 {
     313             :                         logw(asfd, cntr,
     314             :                           "could not split %s into namespace and name on %s\n",
     315             :                                 nspace, path);
     316             :                         goto end;
     317             :                 }
     318             :                 *name='\0';
     319             :                 name++;
     320             : 
     321             :                 if(extattr_string_to_namespace(nspace, &cnspace))
     322             :                 {
     323             :                         logw(asfd, cntr,
     324             :                                 "could not convert %s into namespace on %s\n",
     325             :                                 nspace, path);
     326             :                         goto end;
     327             :                 }
     328             : 
     329             :                 //printf("set_link: %d %s %s %s\n", cnspace, nspace, name, value);
     330             :                 if((cnt=extattr_set_link(path,
     331             :                         cnspace, name, value, vlen))!=vlen)
     332             :                 {
     333             :                         logw(asfd, cntr,
     334             :                                 "extattr_set_link error on %s %zd!=%zd: %s\n",
     335             :                                 path, cnt, vlen, strerror(errno));
     336             :                         goto end;
     337             :                 }
     338             : 
     339             :                 free_w(&nspace);
     340             :                 free_w(&value);
     341             :         }
     342             :         ret=0;
     343             : end:
     344             :         free_w(&nspace);
     345             :         free_w(&value);
     346             :         return ret;
     347             : }
     348             : 
     349             : int set_xattr(struct asfd *asfd, const char *path,
     350             :         const char *xattrtext,
     351             :         size_t xlen, char metacmd, struct cntr *cntr)
     352             : {
     353             :         switch(metacmd)
     354             :         {
     355             :                 case META_XATTR_BSD:
     356             :                         return do_set_xattr_bsd(asfd, path,
     357             :                                 xattrtext, xlen, cntr);
     358             :                 default:
     359             :                         logp("unknown xattr type: %c\n", metacmd);
     360             :                         logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
     361             :                         break;
     362             :         }
     363             :         return -1;
     364             : }
     365             : #elif defined(HAVE_SYS_XATTR_H)
     366           9 : int has_xattr(const char *path)
     367             : {
     368           9 :         if(llistxattr(path, NULL, 0)>0) return 1;
     369           9 :         return 0;
     370             : }
     371             : 
     372           9 : int get_xattr(struct asfd *asfd, const char *path,
     373             :         char **xattrtext, size_t *xlen, struct cntr *cntr)
     374             : {
     375           9 :         char *z=NULL;
     376             :         ssize_t len;
     377           9 :         int have_acl=0;
     378           9 :         char *toappend=NULL;
     379           9 :         char *xattrlist=NULL;
     380           9 :         ssize_t totallen=0;
     381           9 :         ssize_t maxlen=0xFFFFFFFF/2;
     382             : 
     383           9 :         if((len=llistxattr(path, NULL, 0))<0)
     384             :         {
     385             :                 logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
     386           0 :                         path, len, strerror(errno));
     387           0 :                 return 0; // carry on
     388             :         }
     389           9 :         if(!(xattrlist=(char *)calloc_w(1, len, __func__)))
     390             :                 return -1;
     391           9 :         if((len=llistxattr(path, xattrlist, len))<0)
     392             :         {
     393             :                 logw(asfd, cntr, "could not llistxattr '%s': %zd %s\n",
     394           0 :                         path, len, strerror(errno));
     395           0 :                 free_w(&xattrlist);
     396           0 :                 return 0; // carry on
     397             :         }
     398             : 
     399           9 :         if(xattrtext && *xattrtext)
     400             :         {
     401             :                 // Already have some meta text, which means that some
     402             :                 // ACLs were set.
     403           0 :                 have_acl++;
     404             :         }
     405             : 
     406          32 :         for(z=xattrlist; z-xattrlist <= len; z=strchr(z, '\0')+1)
     407             :         {
     408             :                 char tmp1[9];
     409             :                 char tmp2[9];
     410          23 :                 char *val=NULL;
     411             :                 ssize_t vlen;
     412          23 :                 ssize_t zlen=0;
     413          23 :                 ssize_t newlen=0;
     414             : 
     415          23 :                 if((zlen=strlen(z))>maxlen)
     416             :                 {
     417             :                         logw(asfd, cntr, "xattr element of '%s' too long: %zd\n",
     418           0 :                                 path, zlen);
     419           0 :                         free_w(&toappend);
     420           0 :                         break;
     421             :                 }
     422             : 
     423          23 :                 if(have_acl)
     424             :                 {
     425             :                         int c=0;
     426             :                         int skip=0;
     427             :                         // skip xattr entries that were already saved as ACLs.
     428           0 :                         for(c=0; xattr_acl_skiplist[c]; c++)
     429             :                         {
     430           0 :                                 if(!strcmp(z, xattr_acl_skiplist[c]))
     431             :                                 {
     432             :                                         skip++;
     433             :                                         break;
     434             :                                 }
     435             :                         }
     436           9 :                         if(skip) continue;
     437             :                 }
     438             : 
     439          23 :                 if((vlen=lgetxattr(path, z, NULL, 0))<0)
     440             :                 {
     441             :                         logw(asfd, cntr,
     442             :                                 "could not lgetxattr on %s for %s: %zd %s\n",
     443           9 :                                 path, z, vlen, strerror(errno));
     444           9 :                         continue;
     445             :                 }
     446          14 :                 if(vlen)
     447             :                 {
     448          10 :                         if(!(val=(char *)malloc_w(vlen+1, __func__)))
     449             :                         {
     450           0 :                                 free_w(&xattrlist);
     451           0 :                                 free_w(&toappend);
     452           0 :                                 return -1;
     453             :                         }
     454          10 :                         if((vlen=lgetxattr(path, z, val, vlen))<0)
     455             :                         {
     456             :                                 logw(asfd, cntr,
     457             :                                   "could not lgetxattr %s for %s: %zd %s\n",
     458           0 :                                         path, z, vlen, strerror(errno));
     459           0 :                                 free_w(&val);
     460           0 :                                 continue;
     461             :                         }
     462          10 :                         val[vlen]='\0';
     463             : 
     464          10 :                         if(vlen>maxlen)
     465             :                         {
     466             :                                 logw(asfd, cntr,
     467             :                                         "xattr value of '%s' too long: %zd\n",
     468           0 :                                         path, vlen);
     469           0 :                                 free_w(&toappend);
     470           0 :                                 free_w(&val);
     471           0 :                                 break;
     472             :                         }
     473             :                 }
     474             : 
     475          14 :                 snprintf(tmp1, sizeof(tmp1), "%08X", (unsigned int)zlen);
     476          14 :                 snprintf(tmp2, sizeof(tmp2), "%08X", (unsigned int)vlen);
     477          14 :                 newlen=totallen+8+zlen+8+vlen;
     478          14 :                 if(!(toappend=(char *)realloc_w(toappend, newlen, __func__)))
     479             :                 {
     480           0 :                         free_w(&val);
     481           0 :                         free_w(&xattrlist);
     482           0 :                         return -1;
     483             :                 }
     484          14 :                 memcpy(toappend+totallen, tmp1, 8);
     485          14 :                 totallen+=8;
     486          14 :                 memcpy(toappend+totallen, z, zlen);
     487          14 :                 totallen+=zlen;
     488          14 :                 memcpy(toappend+totallen, tmp2, 8);
     489          14 :                 totallen+=8;
     490          14 :                 memcpy(toappend+totallen, val, vlen);
     491          14 :                 totallen+=vlen;
     492          14 :                 free_w(&val);
     493             : 
     494          14 :                 if(totallen>maxlen)
     495             :                 {
     496             :                         logw(asfd, cntr,
     497             :                                 "xattr length of '%s' grew too long: %zd\n",
     498           0 :                                 path, totallen);
     499           0 :                         free_w(&val);
     500           0 :                         free_w(&toappend);
     501           0 :                         free_w(&xattrlist);
     502           0 :                         return 0; // carry on
     503             :                 }
     504             :         }
     505             : 
     506           9 :         if(toappend)
     507             :         {
     508             :                 char tmp3[10];
     509           9 :                 size_t newlen=0;
     510             :                 snprintf(tmp3, sizeof(tmp3), "%c%08X",
     511           9 :                         META_XATTR, (unsigned int)totallen);
     512           9 :                 newlen=(*xlen)+9+totallen;
     513           9 :                 if(!(*xattrtext=(char *)
     514           9 :                         realloc_w(*xattrtext, newlen, __func__)))
     515             :                 {
     516           0 :                         free_w(&toappend);
     517           0 :                         free_w(&xattrlist);
     518           0 :                         return -1;
     519             :                 }
     520           9 :                 memcpy(*xattrtext, tmp3, 9);
     521           9 :                 (*xlen)+=9;
     522           9 :                 memcpy((*xattrtext)+(*xlen), toappend, totallen);
     523           9 :                 (*xlen)+=totallen;
     524           9 :                 free_w(&toappend);
     525             :         }
     526           9 :         free_w(&xattrlist);
     527           9 :         return 0;
     528             : }
     529             : 
     530           9 : static int do_set_xattr(struct asfd *asfd,
     531             :         const char *path,
     532             :         const char *xattrtext, size_t xlen, struct cntr *cntr)
     533             : {
     534           9 :         size_t l=0;
     535           9 :         int ret=-1;
     536           9 :         char *data=NULL;
     537           9 :         char *name=NULL;
     538           9 :         char *value=NULL;
     539             : 
     540           9 :         data=(char *)xattrtext;
     541           9 :         l=xlen;
     542          32 :         while(l>0)
     543             :         {
     544          14 :                 ssize_t s=0;
     545          14 :                 free_w(&name);
     546          14 :                 free_w(&value);
     547             : 
     548          14 :                 if(!(name=get_next_xattr_str(asfd, &data, &l,
     549          14 :                         cntr, &s, path))
     550          28 :                   || !(value=get_next_xattr_str(asfd, &data, &l,
     551          14 :                         cntr, &s, path)))
     552             :                                 goto end;
     553          14 :                 if(lsetxattr(path, name, value, s, 0))
     554             :                 {
     555             :                         logw(asfd, cntr, "lsetxattr error on %s: %s\n",
     556           0 :                                 path, strerror(errno));
     557           0 :                         goto end;
     558             :                 }
     559             :         }
     560             : 
     561             :         ret=0;
     562             : end:
     563           9 :         free_w(&name);
     564           9 :         free_w(&value);
     565           9 :         return ret;
     566             : }
     567             : 
     568           9 : int set_xattr(struct asfd *asfd, const char *path,
     569             :         const char *xattrtext, size_t xlen, char metacmd, struct cntr *cntr)
     570             : {
     571           9 :         switch(metacmd)
     572             :         {
     573             :                 case META_XATTR:
     574             :                         return do_set_xattr(asfd,
     575           9 :                                 path, xattrtext, xlen, cntr);
     576             :                 default:
     577           0 :                         logp("unknown xattr type: %c\n", metacmd);
     578           0 :                         logw(asfd, cntr, "unknown xattr type: %c\n", metacmd);
     579             :                         break;
     580             :         }
     581           0 :         return -1;
     582             : }
     583             : #endif // HAVE_SYS_XATTR_H
     584             : 
     585             : #endif // HAVE_XATTR

Generated by: LCOV version 1.10