PageRenderTime 36ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/service-group.c

https://gitlab.com/mikey-austin/libnss-dbng
C | 421 lines | 337 code | 66 blank | 18 comment | 50 complexity | 59f5824c341e96b6b24af4db360368fb MD5 | raw file
  1. /**
  2. * @file service-group.c
  3. * @brief Implements group service abstraction interface.
  4. * @author Mikey Austin
  5. * @date 2015
  6. */
  7. #include <string.h>
  8. #include <regex.h>
  9. #include "service-group.h"
  10. #include "utils.h"
  11. #define ERRBUFLEN 256
  12. #define NMATCH 4 /* A match per group column. */
  13. static int validate(SERVICE *, const KEY *, const REC *);
  14. static void print(SERVICE *, const KEY *, const REC *);
  15. static int parse(SERVICE *, const char *, KEY *, REC *);
  16. static KEY *new_key(SERVICE *);
  17. static REC *new_rec(SERVICE *);
  18. static void key_init(SERVICE *, KEY *, enum KEY_TYPE, void *);
  19. static void pack_key(SERVICE *, const KEY *, DBT *);
  20. static void pack_rec(SERVICE *, const REC *, DBT *);
  21. static void unpack_key(SERVICE *, KEY *, const DBT *);
  22. static void unpack_rec(SERVICE *, REC *, const DBT *);
  23. static int key_creator(DB *, const DBT *, const DBT *, DBT *);
  24. static size_t rec_size(SERVICE *, const REC *);
  25. static size_t key_size(SERVICE *, const KEY *);
  26. extern void
  27. service_group_init(SERVICE *service)
  28. {
  29. memset(service, 0, sizeof(*service));
  30. service->type = TYPE_GROUP;
  31. service->pri = GROUP_PRI;
  32. service->sec = GROUP_SEC;
  33. /* Set implemented functions. */
  34. service->print = print;
  35. service->validate = validate;
  36. service->parse = parse;
  37. service->key_creator = key_creator;
  38. service->pack_key = pack_key;
  39. service->unpack_key = unpack_key;
  40. service->pack_rec = pack_rec;
  41. service->unpack_rec = unpack_rec;
  42. service->rec_size = rec_size;
  43. service->key_size = key_size;
  44. service->new_key = new_key;
  45. service->new_rec = new_rec;
  46. service->key_init = key_init;
  47. service->cleanup = NULL;
  48. /* Set inherited functions. */
  49. service->get = service_get_rec;
  50. service->set = service_set_rec;
  51. service->next = service_next_rec;
  52. service->delete = service_delete_rec;
  53. service->truncate = service_truncate;
  54. service->start_txn = service_start_txn;
  55. service->commit = service_commit_txn;
  56. service->rollback = service_rollback_txn;
  57. }
  58. static void
  59. print(SERVICE *service, const KEY *key, const REC *rec)
  60. {
  61. const GROUP_KEY *gkey = (const GROUP_KEY *) key;
  62. const GROUP_REC *grec = (const GROUP_REC *) rec;
  63. char **member = NULL;
  64. int i;
  65. printf("%s:%s:%ld:",
  66. grec->name, grec->passwd,
  67. (unsigned long) grec->gid);
  68. for(member = grec->members, i = 0;
  69. member != NULL && *member != NULL;
  70. member++, i++)
  71. {
  72. printf("%s%s", (i > 0 ? "," : ""), *member);
  73. }
  74. printf("\n");
  75. }
  76. static int
  77. parse(SERVICE *service, const char *raw, KEY *key, REC *rec)
  78. {
  79. GROUP_KEY *gkey = (GROUP_KEY *) key;
  80. GROUP_REC *grec = (GROUP_REC *) rec;
  81. int ret, res = 0, i, len;
  82. regex_t regex;
  83. regmatch_t matches[NMATCH + 1];
  84. char err_buf[ERRBUFLEN];
  85. static char buf[SERVICE_REC_MAX];
  86. size_t remaining = sizeof(buf);
  87. char *p_buf = buf, *c_buf, *member;
  88. memset(&regex, 0, sizeof(regex));
  89. memset(gkey, 0, sizeof(*gkey));
  90. memset(grec, 0, sizeof(*grec));
  91. memset(&buf, 0, sizeof(buf));
  92. gkey->base.type = PRI;
  93. grec->base.type = TYPE_GROUP;
  94. ret = regcomp(&regex,
  95. "([^:]+):" /* group. */
  96. "([^:]+):" /* passwd. */
  97. "([[:digit:]]+):" /* gid. */
  98. "([^:]*)$", /* members (may be empty). */
  99. REG_EXTENDED);
  100. if(ret != 0) {
  101. regerror(ret, &regex, err_buf, ERRBUFLEN);
  102. warnx("regcomp: %s", err_buf);
  103. goto cleanup;
  104. }
  105. ret = regexec(&regex, raw, NMATCH + 1, matches, 0);
  106. if(ret != 0) {
  107. if(ret != REG_NOMATCH) {
  108. regerror(ret, &regex, err_buf, ERRBUFLEN);
  109. warnx("regcomp: %s", err_buf);
  110. }
  111. goto cleanup;
  112. }
  113. else {
  114. /* Successful match. */
  115. for(i = 1; i < NMATCH; i++) {
  116. len = matches[i].rm_eo - matches[i].rm_so;
  117. if((remaining -= (len + 1)) <= 0) {
  118. warnx("regexec: parsed record too large");
  119. goto cleanup;
  120. }
  121. strncpy(p_buf, (raw + matches[i].rm_so), len);
  122. p_buf[len] = '\0';
  123. switch(i) {
  124. case 1:
  125. gkey->data.pri = grec->name = p_buf;
  126. break;
  127. case 2:
  128. grec->passwd = p_buf;
  129. break;
  130. case 3:
  131. grec->gid = atoi(p_buf);
  132. break;
  133. }
  134. p_buf += (len + 1);
  135. }
  136. /*
  137. * Sanitize the members string my removing preceding/trailing commas & empty
  138. * entries.
  139. */
  140. const char *raw_members = raw + matches[4].rm_so;
  141. int raw_members_len = strlen(raw_members), seen_member = 0, j;
  142. char safe_members[raw_members_len + 1];
  143. memset(safe_members, 0, raw_members_len + 1);
  144. for(i = 0, j = 0; i < raw_members_len; i++) {
  145. if(raw_members[i] == ',') {
  146. if(i == 0 || raw_members[i - 1] == ',' || !seen_member)
  147. continue;
  148. }
  149. else if(i > 0) {
  150. seen_member = 1;
  151. }
  152. safe_members[j++] = raw_members[i];
  153. }
  154. safe_members[j] = '\0';
  155. if(j > 0 && safe_members[j - 1] == ',')
  156. safe_members[j - 1] = '\0';
  157. /* Count the number of members by counting the number of commas. */
  158. grec->count = (strlen(safe_members) > 0 ? 1 : 0);
  159. if(grec->count > 0) {
  160. c_buf = strchr(safe_members, ',');
  161. while(c_buf != NULL) {
  162. grec->count++;
  163. c_buf = strchr(++c_buf, ',');
  164. }
  165. len = ((grec->count + 1) * sizeof(char *));
  166. remaining -= len;
  167. if(grec->count > 0 && remaining > 0) {
  168. /* Reserve space for pointers. */
  169. grec->members = (char **) p_buf;
  170. p_buf += len;
  171. for(i = 0, member = strtok(safe_members, ",");
  172. remaining > 0 && i < grec->count && member != NULL;
  173. i++, member = strtok(NULL, ","))
  174. {
  175. grec->members[i] = p_buf;
  176. strcpy(p_buf, member);
  177. len = strlen(member);
  178. p_buf[len] = '\0';
  179. p_buf += (len + 1);
  180. remaining -= (len + 1);
  181. }
  182. }
  183. }
  184. res = 1;
  185. }
  186. cleanup:
  187. regfree(&regex);
  188. return res;
  189. }
  190. static KEY
  191. *new_key(SERVICE *service)
  192. {
  193. return xmalloc(sizeof(GROUP_KEY));
  194. }
  195. static REC
  196. *new_rec(SERVICE *service)
  197. {
  198. return xmalloc(sizeof(GROUP_REC));
  199. }
  200. static void
  201. key_init(SERVICE *service, KEY *key, enum KEY_TYPE type, void *data)
  202. {
  203. GROUP_KEY *gkey = (GROUP_KEY *) key;
  204. gkey->base.type = type;
  205. gkey->data.pri = (char *) data;
  206. }
  207. static int
  208. key_creator(DB *dbp, const DBT *gkey, const DBT *gdata, DBT *skey)
  209. {
  210. GROUP_KEY key;
  211. GROUP_REC rec;
  212. /* Create the secondary index on the gid. */
  213. unpack_rec(NULL, (REC *) &rec, gdata);
  214. key.base.type = SEC;
  215. key.data.sec = rec.gid;
  216. int size = key_size(NULL, (KEY *) &key);
  217. skey->data = xcalloc(1, size);
  218. skey->size = size;
  219. skey->flags = DB_DBT_APPMALLOC;
  220. pack_key(NULL, (KEY *) &key, skey);
  221. return 0;
  222. }
  223. static size_t
  224. rec_size(SERVICE *service, const REC *rec)
  225. {
  226. GROUP_REC *grec = (GROUP_REC *) rec;
  227. size_t size;
  228. char **member;
  229. size = sizeof(grec->gid)
  230. + sizeof(grec->count)
  231. + ((grec->count + 1) * sizeof(char *))
  232. + strlen(grec->name) + 1
  233. + strlen(grec->passwd) + 1;
  234. for(member = grec->members;
  235. member != NULL && *member != NULL;
  236. member++)
  237. {
  238. size += strlen(*member) + 1;
  239. }
  240. return size;
  241. }
  242. static size_t
  243. key_size(SERVICE *service, const KEY *key)
  244. {
  245. GROUP_KEY *gkey = (GROUP_KEY *) key;
  246. return sizeof(gkey->base.type)
  247. + (gkey->base.type == PRI
  248. ? (strlen(gkey->data.pri) + 1)
  249. : sizeof(gkey->data.sec));
  250. }
  251. static void
  252. pack_key(SERVICE *service, const KEY *key, DBT *dbkey)
  253. {
  254. GROUP_KEY *gkey = (GROUP_KEY *) key;
  255. char *buf = dbkey->data, *s;
  256. switch(gkey->base.type) {
  257. case PRI:
  258. memcpy(buf + sizeof(gkey->base.type), gkey->data.pri,
  259. strlen(gkey->data.pri) + 1);
  260. break;
  261. case SEC:
  262. memcpy(buf + sizeof(gkey->base.type), &gkey->data.sec,
  263. sizeof(gkey->data.sec));
  264. break;
  265. }
  266. }
  267. static void
  268. pack_rec(SERVICE *service, const REC *rec, DBT *dbrec)
  269. {
  270. GROUP_REC *grec = (GROUP_REC *) rec;
  271. char *buf = NULL, *s, **member;
  272. int len, slen = 0;
  273. /* Reserve space for the record and the number of group members. */
  274. buf = dbrec->data;
  275. len = dbrec->size;
  276. s = buf;
  277. memcpy(s, &grec->gid, (slen = sizeof(grec->gid)));
  278. s += slen;
  279. memcpy(s, grec->name, (slen = (strlen(grec->name) + 1)));
  280. s += slen;
  281. memcpy(s, grec->passwd, (slen = (strlen(grec->passwd) + 1)));
  282. s += slen;
  283. /* Reserve space for count and member pointers. */
  284. memcpy(s, &grec->count, (slen = sizeof(grec->count)));
  285. s += slen + ((grec->count + 1) * sizeof(char *));
  286. for(member = grec->members;
  287. member != NULL && *member != NULL;
  288. member++)
  289. {
  290. memcpy(s, *member, (slen = (strlen(*member) + 1)));
  291. s += slen;
  292. }
  293. memset(dbrec, 0, sizeof(*dbrec));
  294. dbrec->data = buf;
  295. dbrec->size = len;
  296. }
  297. static void
  298. unpack_key(SERVICE *service, KEY *key, const DBT *dbkey)
  299. {
  300. GROUP_KEY *gkey = (GROUP_KEY *) key;
  301. char *buf = (char *) dbkey->data;
  302. memset(gkey, 0, sizeof(*gkey));
  303. gkey->base.type = *((enum KEY_TYPE *) buf);
  304. buf += sizeof(gkey->base.type);
  305. switch(gkey->base.type) {
  306. case PRI:
  307. gkey->data.pri = buf;
  308. break;
  309. case SEC:
  310. memcpy(&gkey->data.sec, buf, sizeof(gkey->data.sec));
  311. break;
  312. }
  313. }
  314. static void
  315. unpack_rec(SERVICE *service, REC *rec, const DBT *dbrec)
  316. {
  317. GROUP_REC *grec = (GROUP_REC *) rec;
  318. char *buf = (char *) dbrec->data;
  319. int i, len, remaining = dbrec->size;
  320. memset(grec, 0, sizeof(*grec));
  321. grec->base.type = TYPE_GROUP;
  322. memcpy(&grec->gid, buf, sizeof(grec->gid));
  323. buf += sizeof(grec->gid);
  324. remaining -= sizeof(grec->gid);
  325. grec->name = buf;
  326. buf += (len = (strlen(grec->name) + 1));
  327. remaining -= len;
  328. grec->passwd = buf;
  329. buf += (len = (strlen(grec->passwd) + 1));
  330. remaining -= len;
  331. memcpy(&grec->count, buf, sizeof(grec->count));
  332. buf += sizeof(grec->count);
  333. remaining -= sizeof(grec->count);
  334. grec->members = (char **) buf;
  335. buf += (len = ((grec->count + 1) * sizeof(char *)));
  336. remaining -= len;
  337. for(i = 0; i < grec->count && remaining > 0; i++) {
  338. grec->members[i] = buf;
  339. buf += (len = (strlen(grec->members[i]) + 1));
  340. remaining -= len;
  341. }
  342. grec->members[i] = NULL;
  343. }
  344. static int
  345. validate(SERVICE *service, const KEY *key, const REC *rec)
  346. {
  347. const GROUP_REC *prec = (const GROUP_REC *) rec;
  348. gid_t gid = getgid();
  349. if(MIN_GID > 0) {
  350. return ((gid < MIN_GID && prec->gid >= MIN_GID) || prec->gid == gid);
  351. }
  352. else {
  353. return 1;
  354. }
  355. }