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

Generated by: LCOV version 1.10