nss_action_parse.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* Parse a service line from nsswitch.conf.
  2. Copyright (c) 1996-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <nsswitch.h>
  16. #include <ctype.h>
  17. #include <string.h>
  18. #include <stdbool.h>
  19. /* Staging area during parsing. */
  20. #define DYNARRAY_STRUCT action_list
  21. #define DYNARRAY_ELEMENT struct nss_action
  22. #define DYNARRAY_PREFIX action_list_
  23. #include <malloc/dynarray-skeleton.c>
  24. /* Skip whitespace in line[]. */
  25. #define SKIP_WS() \
  26. while (line[0] != '\0' && isspace (line[0])) \
  27. ++line;
  28. /* Read the source names:
  29. `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
  30. */
  31. static bool
  32. nss_action_parse (const char *line, struct action_list *result)
  33. {
  34. while (1)
  35. {
  36. SKIP_WS ();
  37. if (line[0] == '\0')
  38. /* No more sources specified. */
  39. return true;
  40. /* Read <source> identifier. */
  41. const char *name = line;
  42. while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
  43. && line[0] != '[')
  44. ++line;
  45. if (name == line)
  46. return true;
  47. struct nss_action new_service
  48. = { .module = __nss_module_allocate (name, line - name), };
  49. if (new_service.module == NULL)
  50. {
  51. /* Memory allocation error. */
  52. action_list_mark_failed (result);
  53. return false;
  54. }
  55. nss_action_set_all (&new_service, NSS_ACTION_CONTINUE);
  56. nss_action_set (&new_service, NSS_STATUS_SUCCESS, NSS_ACTION_RETURN);
  57. nss_action_set (&new_service, NSS_STATUS_RETURN, NSS_ACTION_RETURN);
  58. SKIP_WS ();
  59. if (line[0] == '[')
  60. {
  61. /* Read criterions. */
  62. /* Skip the '['. */
  63. ++line;
  64. SKIP_WS ();
  65. do
  66. {
  67. int not;
  68. enum nss_status status;
  69. lookup_actions action;
  70. /* Grok ! before name to mean all statuses but that one. */
  71. not = line[0] == '!';
  72. if (not)
  73. ++line;
  74. /* Read status name. */
  75. name = line;
  76. while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
  77. && line[0] != '=' && line[0] != ']')
  78. ++line;
  79. /* Compare with known statuses. */
  80. if (line - name == 7)
  81. {
  82. if (__strncasecmp_l (name, "SUCCESS", 7,
  83. _nl_C_locobj_ptr) == 0)
  84. status = NSS_STATUS_SUCCESS;
  85. else if (__strncasecmp_l (name, "UNAVAIL", 7,
  86. _nl_C_locobj_ptr) == 0)
  87. status = NSS_STATUS_UNAVAIL;
  88. else
  89. return false;
  90. }
  91. else if (line - name == 8)
  92. {
  93. if (__strncasecmp_l (name, "NOTFOUND", 8,
  94. _nl_C_locobj_ptr) == 0)
  95. status = NSS_STATUS_NOTFOUND;
  96. else if (__strncasecmp_l (name, "TRYAGAIN", 8,
  97. _nl_C_locobj_ptr) == 0)
  98. status = NSS_STATUS_TRYAGAIN;
  99. else
  100. return false;
  101. }
  102. else
  103. return false;
  104. SKIP_WS ();
  105. if (line[0] != '=')
  106. return false;
  107. /* Skip the '='. */
  108. ++line;
  109. SKIP_WS ();
  110. name = line;
  111. while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
  112. && line[0] != '=' && line[0] != ']')
  113. ++line;
  114. if (line - name == 6
  115. && __strncasecmp_l (name, "RETURN", 6, _nl_C_locobj_ptr) == 0)
  116. action = NSS_ACTION_RETURN;
  117. else if (line - name == 8
  118. && __strncasecmp_l (name, "CONTINUE", 8,
  119. _nl_C_locobj_ptr) == 0)
  120. action = NSS_ACTION_CONTINUE;
  121. else if (line - name == 5
  122. && __strncasecmp_l (name, "MERGE", 5,
  123. _nl_C_locobj_ptr) == 0)
  124. action = NSS_ACTION_MERGE;
  125. else
  126. return false;
  127. if (not)
  128. {
  129. /* Save the current action setting for this status,
  130. set them all to the given action, and reset this one. */
  131. const lookup_actions save
  132. = nss_action_get (&new_service, status);
  133. nss_action_set_all (&new_service, action);
  134. nss_action_set (&new_service, status, save);
  135. }
  136. else
  137. nss_action_set (&new_service, status, action);
  138. SKIP_WS ();
  139. }
  140. while (line[0] != ']');
  141. /* Skip the ']'. */
  142. ++line;
  143. }
  144. action_list_add (result, new_service);
  145. }
  146. }
  147. nss_action_list
  148. __nss_action_parse (const char *line)
  149. {
  150. struct action_list list;
  151. action_list_init (&list);
  152. if (nss_action_parse (line, &list))
  153. {
  154. nss_action_list retval;
  155. size_t size;
  156. struct nss_action null_service
  157. = { .module = NULL, };
  158. action_list_add (&list, null_service);
  159. size = action_list_size (&list);
  160. retval = __nss_action_allocate (action_list_begin (&list), size);
  161. action_list_free (&list);
  162. return retval;
  163. }
  164. else if (action_list_has_failed (&list))
  165. {
  166. /* Memory allocation error. */
  167. __set_errno (ENOMEM);
  168. return NULL;
  169. }
  170. else
  171. {
  172. /* Parse error. */
  173. __set_errno (EINVAL);
  174. return NULL;
  175. }
  176. }