PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/avahi/avahi-0.6.19/avahi-common/domain.c

https://bitbucket.org/thelearninglabs/uclinux-distro-tll-public
C | 611 lines | 388 code | 181 blank | 42 comment | 144 complexity | 85ba261a320705d6af69f5cbff950959 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0, Unlicense, GPL-2.0, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0, ISC, MIT, 0BSD, LGPL-2.0
  1. /* $Id: domain.c 1202 2006-04-24 21:52:34Z lennart $ */
  2. /***
  3. This file is part of avahi.
  4. avahi is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. avahi is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
  11. Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with avahi; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  15. USA.
  16. ***/
  17. #ifdef HAVE_CONFIG_H
  18. #include <config.h>
  19. #endif
  20. #include <string.h>
  21. #include <unistd.h>
  22. #include <fcntl.h>
  23. #include <errno.h>
  24. #include <limits.h>
  25. #include <stdio.h>
  26. #include <ctype.h>
  27. #include <stdlib.h>
  28. #include <assert.h>
  29. #include "domain.h"
  30. #include "malloc.h"
  31. #include "error.h"
  32. #include "address.h"
  33. #include "utf8.h"
  34. /* Read the first label from string *name, unescape "\" and write it to dest */
  35. char *avahi_unescape_label(const char **name, char *dest, size_t size) {
  36. unsigned i = 0;
  37. char *d;
  38. assert(dest);
  39. assert(size > 0);
  40. assert(name);
  41. d = dest;
  42. for (;;) {
  43. if (i >= size)
  44. return NULL;
  45. if (**name == '.') {
  46. (*name)++;
  47. break;
  48. }
  49. if (**name == 0)
  50. break;
  51. if (**name == '\\') {
  52. /* Escaped character */
  53. (*name) ++;
  54. if (**name == 0)
  55. /* Ending NUL */
  56. return NULL;
  57. else if (**name == '\\' || **name == '.') {
  58. /* Escaped backslash or dot */
  59. *(d++) = *((*name) ++);
  60. i++;
  61. } else if (isdigit(**name)) {
  62. int n;
  63. /* Escaped literal ASCII character */
  64. if (!isdigit(*(*name+1)) || !isdigit(*(*name+2)))
  65. return NULL;
  66. n = ((uint8_t) (**name - '0') * 100) + ((uint8_t) (*(*name+1) - '0') * 10) + ((uint8_t) (*(*name +2) - '0'));
  67. if (n > 255 || n == 0)
  68. return NULL;
  69. *(d++) = (char) n;
  70. i++;
  71. (*name) += 3;
  72. } else
  73. return NULL;
  74. } else {
  75. /* Normal character */
  76. *(d++) = *((*name) ++);
  77. i++;
  78. }
  79. }
  80. assert(i < size);
  81. *d = 0;
  82. if (!avahi_utf8_valid(dest))
  83. return NULL;
  84. return dest;
  85. }
  86. /* Escape "\" and ".", append \0 */
  87. char *avahi_escape_label(const char* src, size_t src_length, char **ret_name, size_t *ret_size) {
  88. char *r;
  89. assert(src);
  90. assert(ret_name);
  91. assert(*ret_name);
  92. assert(ret_size);
  93. assert(*ret_size > 0);
  94. r = *ret_name;
  95. while (src_length > 0) {
  96. if (*src == '.' || *src == '\\') {
  97. /* Dot or backslash */
  98. if (*ret_size < 3)
  99. return NULL;
  100. *((*ret_name) ++) = '\\';
  101. *((*ret_name) ++) = *src;
  102. (*ret_size) -= 2;
  103. } else if (
  104. *src == '_' ||
  105. *src == '-' ||
  106. (*src >= '0' && *src <= '9') ||
  107. (*src >= 'a' && *src <= 'z') ||
  108. (*src >= 'A' && *src <= 'Z')) {
  109. /* Proper character */
  110. if (*ret_size < 2)
  111. return NULL;
  112. *((*ret_name)++) = *src;
  113. (*ret_size) --;
  114. } else {
  115. /* Everything else */
  116. if (*ret_size < 5)
  117. return NULL;
  118. *((*ret_name) ++) = '\\';
  119. *((*ret_name) ++) = '0' + (char) ((uint8_t) *src / 100);
  120. *((*ret_name) ++) = '0' + (char) (((uint8_t) *src / 10) % 10);
  121. *((*ret_name) ++) = '0' + (char) ((uint8_t) *src % 10);
  122. (*ret_size) -= 4;
  123. }
  124. src_length --;
  125. src++;
  126. }
  127. **ret_name = 0;
  128. return r;
  129. }
  130. char *avahi_normalize_name(const char *s, char *ret_s, size_t size) {
  131. int empty = 1;
  132. char *r;
  133. assert(s);
  134. assert(ret_s);
  135. assert(size > 0);
  136. r = ret_s;
  137. *ret_s = 0;
  138. while (*s) {
  139. char label[AVAHI_LABEL_MAX];
  140. if (!(avahi_unescape_label(&s, label, sizeof(label))))
  141. return NULL;
  142. if (label[0] == 0) {
  143. if (*s == 0 && empty)
  144. return ret_s;
  145. return NULL;
  146. }
  147. if (!empty) {
  148. if (size < 1)
  149. return NULL;
  150. *(r++) = '.';
  151. size--;
  152. } else
  153. empty = 0;
  154. avahi_escape_label(label, strlen(label), &r, &size);
  155. }
  156. return ret_s;
  157. }
  158. char *avahi_normalize_name_strdup(const char *s) {
  159. char t[AVAHI_DOMAIN_NAME_MAX];
  160. assert(s);
  161. if (!(avahi_normalize_name(s, t, sizeof(t))))
  162. return NULL;
  163. return avahi_strdup(t);
  164. }
  165. int avahi_domain_equal(const char *a, const char *b) {
  166. assert(a);
  167. assert(b);
  168. if (a == b)
  169. return 1;
  170. for (;;) {
  171. char ca[AVAHI_LABEL_MAX], cb[AVAHI_LABEL_MAX], *r;
  172. r = avahi_unescape_label(&a, ca, sizeof(ca));
  173. assert(r);
  174. r = avahi_unescape_label(&b, cb, sizeof(cb));
  175. assert(r);
  176. if (strcasecmp(ca, cb))
  177. return 0;
  178. if (!*a && !*b)
  179. return 1;
  180. }
  181. return 1;
  182. }
  183. int avahi_is_valid_service_type_generic(const char *t) {
  184. assert(t);
  185. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
  186. return 0;
  187. do {
  188. char label[AVAHI_LABEL_MAX];
  189. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  190. return 0;
  191. if (strlen(label) <= 2 || label[0] != '_')
  192. return 0;
  193. } while (*t);
  194. return 1;
  195. }
  196. int avahi_is_valid_service_type_strict(const char *t) {
  197. char label[AVAHI_LABEL_MAX];
  198. assert(t);
  199. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
  200. return 0;
  201. /* Application name */
  202. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  203. return 0;
  204. if (strlen(label) <= 2 || label[0] != '_')
  205. return 0;
  206. if (!*t)
  207. return 0;
  208. /* _tcp or _udp boilerplate */
  209. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  210. return 0;
  211. if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
  212. return 0;
  213. if (*t)
  214. return 0;
  215. return 1;
  216. }
  217. const char *avahi_get_type_from_subtype(const char *t) {
  218. char label[AVAHI_LABEL_MAX];
  219. const char *ret;
  220. assert(t);
  221. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
  222. return NULL;
  223. /* Subtype name */
  224. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  225. return NULL;
  226. if (strlen(label) <= 2 || label[0] != '_')
  227. return NULL;
  228. if (!*t)
  229. return NULL;
  230. /* String "_sub" */
  231. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  232. return NULL;
  233. if (strcasecmp(label, "_sub"))
  234. return NULL;
  235. if (!*t)
  236. return NULL;
  237. ret = t;
  238. /* Application name */
  239. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  240. return NULL;
  241. if (strlen(label) <= 2 || label[0] != '_')
  242. return NULL;
  243. if (!*t)
  244. return NULL;
  245. /* _tcp or _udp boilerplate */
  246. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  247. return NULL;
  248. if (strcasecmp(label, "_tcp") && strcasecmp(label, "_udp"))
  249. return NULL;
  250. if (*t)
  251. return NULL;
  252. return ret;
  253. }
  254. int avahi_is_valid_service_subtype(const char *t) {
  255. assert(t);
  256. return !!avahi_get_type_from_subtype(t);
  257. }
  258. int avahi_is_valid_domain_name(const char *t) {
  259. int is_first = 1;
  260. assert(t);
  261. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX)
  262. return 0;
  263. do {
  264. char label[AVAHI_LABEL_MAX];
  265. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  266. return 0;
  267. /* Explicitly allow the root domain name */
  268. if (is_first && label[0] == 0 && *t == 0)
  269. return 1;
  270. is_first = 0;
  271. if (label[0] == 0)
  272. return 0;
  273. } while (*t);
  274. return 1;
  275. }
  276. int avahi_is_valid_service_name(const char *t) {
  277. assert(t);
  278. if (strlen(t) >= AVAHI_LABEL_MAX || !*t)
  279. return 0;
  280. return 1;
  281. }
  282. int avahi_is_valid_host_name(const char *t) {
  283. char label[AVAHI_LABEL_MAX];
  284. assert(t);
  285. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX || !*t)
  286. return 0;
  287. if (!(avahi_unescape_label(&t, label, sizeof(label))))
  288. return 0;
  289. if (strlen(label) < 1)
  290. return 0;
  291. if (*t)
  292. return 0;
  293. return 1;
  294. }
  295. unsigned avahi_domain_hash(const char *s) {
  296. unsigned hash = 0;
  297. while (*s) {
  298. char c[AVAHI_LABEL_MAX], *p, *r;
  299. r = avahi_unescape_label(&s, c, sizeof(c));
  300. assert(r);
  301. for (p = c; *p; p++)
  302. hash = 31 * hash + tolower(*p);
  303. }
  304. return hash;
  305. }
  306. int avahi_service_name_join(char *p, size_t size, const char *name, const char *type, const char *domain) {
  307. char escaped_name[AVAHI_LABEL_MAX*4];
  308. char normalized_type[AVAHI_DOMAIN_NAME_MAX];
  309. char normalized_domain[AVAHI_DOMAIN_NAME_MAX];
  310. assert(p);
  311. /* Validity checks */
  312. if ((name && !avahi_is_valid_service_name(name)))
  313. return AVAHI_ERR_INVALID_SERVICE_NAME;
  314. if (!avahi_is_valid_service_type_generic(type))
  315. return AVAHI_ERR_INVALID_SERVICE_TYPE;
  316. if (!avahi_is_valid_domain_name(domain))
  317. return AVAHI_ERR_INVALID_DOMAIN_NAME;
  318. /* Preparation */
  319. if (name) {
  320. size_t l = sizeof(escaped_name);
  321. char *e = escaped_name, *r;
  322. r = avahi_escape_label(name, strlen(name), &e, &l);
  323. assert(r);
  324. }
  325. if (!(avahi_normalize_name(type, normalized_type, sizeof(normalized_type))))
  326. return AVAHI_ERR_INVALID_SERVICE_TYPE;
  327. if (!(avahi_normalize_name(domain, normalized_domain, sizeof(normalized_domain))))
  328. return AVAHI_ERR_INVALID_DOMAIN_NAME;
  329. /* Concatenation */
  330. snprintf(p, size, "%s%s%s.%s", name ? escaped_name : "", name ? "." : "", normalized_type, normalized_domain);
  331. return AVAHI_OK;
  332. }
  333. #ifndef HAVE_STRLCPY
  334. static size_t strlcpy(char *dest, const char *src, size_t n) {
  335. assert(dest);
  336. assert(src);
  337. if (n > 0) {
  338. strncpy(dest, src, n-1);
  339. dest[n-1] = 0;
  340. }
  341. return strlen(src);
  342. }
  343. #endif
  344. int avahi_service_name_split(const char *p, char *name, size_t name_size, char *type, size_t type_size, char *domain, size_t domain_size) {
  345. enum {
  346. NAME,
  347. TYPE,
  348. DOMAIN
  349. } state;
  350. int type_empty = 1, domain_empty = 1;
  351. assert(p);
  352. assert(type);
  353. assert(type_size > 0);
  354. assert(domain);
  355. assert(domain_size > 0);
  356. if (name) {
  357. assert(name_size > 0);
  358. *name = 0;
  359. state = NAME;
  360. } else
  361. state = TYPE;
  362. *type = *domain = 0;
  363. while (*p) {
  364. char buf[64];
  365. if (!(avahi_unescape_label(&p, buf, sizeof(buf))))
  366. return -1;
  367. switch (state) {
  368. case NAME:
  369. strlcpy(name, buf, name_size);
  370. state = TYPE;
  371. break;
  372. case TYPE:
  373. if (buf[0] == '_') {
  374. if (!type_empty) {
  375. if (!type_size)
  376. return AVAHI_ERR_NO_MEMORY;
  377. *(type++) = '.';
  378. type_size --;
  379. } else
  380. type_empty = 0;
  381. if (!(avahi_escape_label(buf, strlen(buf), &type, &type_size)))
  382. return AVAHI_ERR_NO_MEMORY;
  383. break;
  384. }
  385. state = DOMAIN;
  386. /* fall through */
  387. case DOMAIN:
  388. if (!domain_empty) {
  389. if (!domain_size)
  390. return AVAHI_ERR_NO_MEMORY;
  391. *(domain++) = '.';
  392. domain_size --;
  393. } else
  394. domain_empty = 0;
  395. if (!(avahi_escape_label(buf, strlen(buf), &domain, &domain_size)))
  396. return AVAHI_ERR_NO_MEMORY;
  397. break;
  398. }
  399. }
  400. return 0;
  401. }
  402. int avahi_is_valid_fqdn(const char *t) {
  403. char label[AVAHI_LABEL_MAX];
  404. char normalized[AVAHI_DOMAIN_NAME_MAX];
  405. const char *k = t;
  406. AvahiAddress a;
  407. assert(t);
  408. if (strlen(t) >= AVAHI_DOMAIN_NAME_MAX)
  409. return 0;
  410. if (!avahi_is_valid_domain_name(t))
  411. return 0;
  412. /* Check if there are at least two labels*/
  413. if (!(avahi_unescape_label(&k, label, sizeof(label))))
  414. return 0;
  415. if (label[0] == 0 || !k)
  416. return 0;
  417. if (!(avahi_unescape_label(&k, label, sizeof(label))))
  418. return 0;
  419. if (label[0] == 0 || !k)
  420. return 0;
  421. /* Make sure that the name is not an IP address */
  422. if (!(avahi_normalize_name(t, normalized, sizeof(normalized))))
  423. return 0;
  424. if (avahi_address_parse(normalized, AVAHI_PROTO_UNSPEC, &a))
  425. return 0;
  426. return 1;
  427. }