parse_mode.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * parse_mode implementation for busybox
  4. *
  5. * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  8. */
  9. /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */
  10. #include "libbb.h"
  11. /* This function is used from NOFORK applets. It must not allocate anything */
  12. #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
  13. int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode)
  14. {
  15. static const mode_t who_mask[] = {
  16. S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
  17. S_ISUID | S_IRWXU, /* u */
  18. S_ISGID | S_IRWXG, /* g */
  19. S_IRWXO /* o */
  20. };
  21. static const mode_t perm_mask[] = {
  22. S_IRUSR | S_IRGRP | S_IROTH, /* r */
  23. S_IWUSR | S_IWGRP | S_IWOTH, /* w */
  24. S_IXUSR | S_IXGRP | S_IXOTH, /* x */
  25. S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
  26. S_ISUID | S_ISGID, /* s */
  27. S_ISVTX /* t */
  28. };
  29. static const char who_chars[] ALIGN1 = "augo";
  30. static const char perm_chars[] ALIGN1 = "rwxXst";
  31. const char *p;
  32. mode_t wholist;
  33. mode_t permlist;
  34. mode_t new_mode;
  35. char op;
  36. if ((unsigned char)(*s - '0') < 8) {
  37. unsigned long tmp;
  38. char *e;
  39. tmp = strtoul(s, &e, 8);
  40. if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */
  41. return -1;
  42. }
  43. return tmp;
  44. }
  45. new_mode = current_mode;
  46. /* Note: we allow empty clauses, and hence empty modes.
  47. * We treat an empty mode as no change to perms. */
  48. while (*s) { /* Process clauses. */
  49. if (*s == ',') { /* We allow empty clauses. */
  50. ++s;
  51. continue;
  52. }
  53. /* Get a wholist. */
  54. wholist = 0;
  55. WHO_LIST:
  56. p = who_chars;
  57. do {
  58. if (*p == *s) {
  59. wholist |= who_mask[(int)(p-who_chars)];
  60. if (!*++s) {
  61. return -1;
  62. }
  63. goto WHO_LIST;
  64. }
  65. } while (*++p);
  66. do { /* Process action list. */
  67. if ((*s != '+') && (*s != '-')) {
  68. if (*s != '=') {
  69. return -1;
  70. }
  71. /* Since op is '=', clear all bits corresponding to the
  72. * wholist, or all file bits if wholist is empty. */
  73. permlist = ~FILEMODEBITS;
  74. if (wholist) {
  75. permlist = ~wholist;
  76. }
  77. new_mode &= permlist;
  78. }
  79. op = *s++;
  80. /* Check for permcopy. */
  81. p = who_chars + 1; /* Skip 'a' entry. */
  82. do {
  83. if (*p == *s) {
  84. int i = 0;
  85. permlist = who_mask[(int)(p-who_chars)]
  86. & (S_IRWXU | S_IRWXG | S_IRWXO)
  87. & new_mode;
  88. do {
  89. if (permlist & perm_mask[i]) {
  90. permlist |= perm_mask[i];
  91. }
  92. } while (++i < 3);
  93. ++s;
  94. goto GOT_ACTION;
  95. }
  96. } while (*++p);
  97. /* It was not a permcopy, so get a permlist. */
  98. permlist = 0;
  99. PERM_LIST:
  100. p = perm_chars;
  101. do {
  102. if (*p == *s) {
  103. if ((*p != 'X')
  104. || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH))
  105. ) {
  106. permlist |= perm_mask[(int)(p-perm_chars)];
  107. }
  108. if (!*++s) {
  109. break;
  110. }
  111. goto PERM_LIST;
  112. }
  113. } while (*++p);
  114. GOT_ACTION:
  115. if (permlist) { /* The permlist was nonempty. */
  116. mode_t tmp = wholist;
  117. if (!wholist) {
  118. mode_t u_mask = umask(0);
  119. umask(u_mask);
  120. tmp = ~u_mask;
  121. }
  122. permlist &= tmp;
  123. if (op == '-') {
  124. new_mode &= ~permlist;
  125. } else {
  126. new_mode |= permlist;
  127. }
  128. }
  129. } while (*s && (*s != ','));
  130. }
  131. return new_mode;
  132. }