ReactOS  0.4.12-dev-57-g7050ac4
idmap.c
Go to the documentation of this file.
1 /* NFSv4.1 client for Windows
2  * Copyright 2012 The Regents of the University of Michigan
3  *
4  * Olga Kornievskaia <aglo@umich.edu>
5  * Casey Bodley <cbodley@umich.edu>
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * without any warranty; without even the implied warranty of merchantability
14  * or fitness for a particular purpose. See the GNU Lesser General Public
15  * License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  */
21 
22 #include <windows.h>
23 #include <strsafe.h>
24 #include <winldap.h>
25 #include <stdlib.h> /* for strtoul() */
26 #include <errno.h>
27 #include <time.h>
28 
29 #include "idmap.h"
30 #include "nfs41_const.h"
31 #include "list.h"
32 #include "daemon_debug.h"
33 
34 
35 #define IDLVL 2 /* dprintf level for idmap logging */
36 
37 #define FILTER_LEN 1024
38 #define NAME_LEN 32
39 #define VAL_LEN 257
40 
41 
42 enum ldap_class {
45 
47 };
48 
49 enum ldap_attr {
55 
57 };
58 
59 #define ATTR_FLAG(attr) (1 << (attr))
60 #define ATTR_ISSET(mask, attr) (((mask) & ATTR_FLAG(attr)) != 0)
61 
62 
63 /* ldap/cache lookups */
64 struct idmap_lookup {
67 #ifdef __REACTOS__
68  uint32_t type;
69 #else
71 #endif
73  const void *value;
74 };
75 
76 
77 #ifndef __REACTOS__
78 /* configuration */
79 static const char CONFIG_FILENAME[] = "C:\\ReactOS\\System32\\drivers\\etc\\ms-nfs41-idmap.conf";
80 #endif
81 
82 struct idmap_config {
83  /* ldap server information */
88 
89  /* ldap schema information */
90  char classes[NUM_CLASSES][NAME_LEN];
91  char attributes[NUM_ATTRIBUTES][NAME_LEN];
92  char base[VAL_LEN];
93 
94  /* caching configuration */
96 };
97 
98 
102 };
103 
105  const char *key;
106  const char *def;
108  size_t offset;
109  size_t max_len;
110 };
111 
112 /* helper macros for declaring config_options */
113 #define OPT_INT(key,def,field) \
114  { key, def, TYPE_INT, FIELD_OFFSET(struct idmap_config, field), 0 }
115 #define OPT_STR(key,def,field,len) \
116  { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, field), len }
117 #define OPT_CLASS(key,def,index) \
118  { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, classes[index]), NAME_LEN }
119 #define OPT_ATTR(key,def,index) \
120  { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, attributes[index]), NAME_LEN }
121 
122 /* table of recognized config options, including type and default value */
123 static const struct config_option g_options[] = {
124  /* server information */
125  OPT_STR("ldap_hostname", "localhost", hostname, NFS41_HOSTNAME_LEN+1),
126  OPT_INT("ldap_port", "389", port),
127  OPT_INT("ldap_version", "3", version),
128  OPT_INT("ldap_timeout", "0", timeout),
129 
130  /* schema information */
131  OPT_STR("ldap_base", "cn=localhost", base, VAL_LEN),
132  OPT_CLASS("ldap_class_users", "user", CLASS_USER),
133  OPT_CLASS("ldap_class_groups", "group", CLASS_GROUP),
134  OPT_ATTR("ldap_attr_username", "cn", ATTR_USER_NAME),
135  OPT_ATTR("ldap_attr_groupname", "cn", ATTR_GROUP_NAME),
136  OPT_ATTR("ldap_attr_gssAuthName", "gssAuthName", ATTR_PRINCIPAL),
137  OPT_ATTR("ldap_attr_uidNumber", "uidNumber", ATTR_UID),
138  OPT_ATTR("ldap_attr_gidNumber", "gidNumber", ATTR_GID),
139 
140  /* caching configuration */
141  OPT_INT("cache_ttl", "60", cache_ttl),
142 };
143 
144 
145 /* parse each line into key-value pairs
146  * accepts 'key = value' or 'key = "value"',
147  * ignores whitespace anywhere outside the ""s */
148 struct config_pair {
149  const char *key, *value;
150  size_t key_len, value_len;
151 };
152 
153 static int config_parse_pair(
154  char *line,
155  struct config_pair *pair)
156 {
157  char *pos = line;
158  int status = NO_ERROR;
159 
160  /* terminate at comment */
161  pos = strchr(line, '#');
162  if (pos) *pos = 0;
163 
164  /* skip whitespace before key */
165  pos = line;
166  while (isspace(*pos)) pos++;
167  pair->key = pos;
168 
169  pos = strchr(pos, '=');
170  if (pos == NULL) {
171  eprintf("missing '='\n");
172  status = ERROR_INVALID_PARAMETER;
173  goto out;
174  }
175 
176  /* skip whitespace after key */
177  pair->key_len = pos - pair->key;
178  while (pair->key_len && isspace(pair->key[pair->key_len-1]))
179  pair->key_len--;
180 
181  if (pair->key_len <= 0) {
182  eprintf("empty key\n");
183  status = ERROR_INVALID_PARAMETER;
184  goto out;
185  }
186 
187  /* skip whitespace after = */
188  pos++;
189  while (isspace(*pos)) pos++;
190 
191  if (*pos == 0) {
192  eprintf("end of line looking for value\n");
193  status = ERROR_INVALID_PARAMETER;
194  goto out;
195  }
196 
197  if (*pos == '\"') {
198  /* value is between the "s */
199  pair->value = pos + 1;
200  pos = strchr(pair->value, '\"');
201  if (pos == NULL) {
202  eprintf("no matching '\"'\n");
203  status = ERROR_INVALID_PARAMETER;
204  goto out;
205  }
206  pair->value_len = pos - pair->value;
207  } else {
208  pair->value = pos;
209  pair->value_len = strlen(pair->value);
210 
211  /* skip whitespace after value */
212  while (pair->value_len && isspace(pair->value[pair->value_len-1]))
213  pair->value_len--;
214  }
215 
216  /* on success, null terminate the key and value */
217  ((char*)pair->key)[pair->key_len] = 0;
218  ((char*)pair->value)[pair->value_len] = 0;
219 out:
220  return status;
221 }
222 
224  const char *str,
225  UINT *id_out)
226 {
227  PCHAR endp;
228  const UINT id = strtoul(str, &endp, 10);
229 
230  /* must convert the whole string */
231  if ((endp - str) < (ptrdiff_t)strlen(str))
232  return FALSE;
233 
234  /* result must fit in 32 bits */
235  if (id == ULONG_MAX && errno == ERANGE)
236  return FALSE;
237 
238  *id_out = id;
239  return TRUE;
240 }
241 
242 /* parse default values from g_options[] into idmap_config */
243 static int config_defaults(
244  struct idmap_config *config)
245 {
246  const struct config_option *option;
247  const int count = ARRAYSIZE(g_options);
248  char *dst;
249  int i, status = NO_ERROR;
250 
251  for (i = 0; i < count; i++) {
252  option = &g_options[i];
253  dst = (char*)config + option->offset;
254 
255  if (option->type == TYPE_INT) {
256  if (!parse_uint(option->def, (UINT*)dst)) {
257  status = ERROR_INVALID_PARAMETER;
258  eprintf("failed to parse default value of %s=\"%s\": "
259  "expected a number\n", option->key, option->def);
260  break;
261  }
262  } else {
263  if (FAILED(StringCchCopyA(dst, option->max_len, option->def))) {
264  status = ERROR_BUFFER_OVERFLOW;
265  eprintf("failed to parse default value of %s=\"%s\": "
266  "buffer overflow > %u\n", option->key, option->def,
267  option->max_len);
268  break;
269  }
270  }
271  }
272  return status;
273 }
274 
276  const struct config_pair *pair,
277  const struct config_option **option)
278 {
279  int i, count = ARRAYSIZE(g_options);
280  int status = ERROR_NOT_FOUND;
281 
282  /* find the config_option by key */
283  for (i = 0; i < count; i++) {
284  if (stricmp(pair->key, g_options[i].key) == 0) {
285  *option = &g_options[i];
286  status = NO_ERROR;
287  break;
288  }
289  }
290  return status;
291 }
292 
293 static int config_load(
294  struct idmap_config *config,
295  const char *filename)
296 {
297  char buffer[1024], *pos;
298  FILE *file;
299  struct config_pair pair;
300  const struct config_option *option;
301  int line = 0;
302  int status = NO_ERROR;
303 
304  /* open the file */
305  file = fopen(filename, "r");
306  if (file == NULL) {
307  eprintf("config_load() failed to open file '%s'\n", filename);
308  goto out;
309  }
310 
311  /* read each line */
312  while (fgets(buffer, sizeof(buffer), file)) {
313  line++;
314 
315  /* skip whitespace */
316  pos = buffer;
317  while (isspace(*pos)) pos++;
318 
319  /* skip comments and empty lines */
320  if (*pos == '#' || *pos == 0)
321  continue;
322 
323  /* parse line into a key=value pair */
324  status = config_parse_pair(buffer, &pair);
325  if (status) {
326  eprintf("error on line %d: %s\n", line, buffer);
327  break;
328  }
329 
330  /* find the config_option by key */
331  status = config_find_option(&pair, &option);
332  if (status) {
333  eprintf("unrecognized option '%s' on line %d: %s\n",
334  pair.key, line, buffer);
335  status = ERROR_INVALID_PARAMETER;
336  break;
337  }
338 
339  if (option->type == TYPE_INT) {
340  if (!parse_uint(pair.value, (UINT*)((char*)config + option->offset))) {
341  status = ERROR_INVALID_PARAMETER;
342  eprintf("expected a number on line %d: %s=\"%s\"\n",
343  line, pair.key, pair.value);
344  break;
345  }
346  } else {
347  if (FAILED(StringCchCopyNA((char*)config + option->offset,
348  option->max_len, pair.value, pair.value_len))) {
349  status = ERROR_BUFFER_OVERFLOW;
350  eprintf("overflow on line %d: %s=\"%s\"\n",
351  line, pair.key, pair.value);
352  break;
353  }
354  }
355  }
356 
357  fclose(file);
358 out:
359  return status;
360 }
361 
362 static int config_init(
363  struct idmap_config *config)
364 {
365  int status;
366 #ifdef __REACTOS__
367  char config_path[MAX_PATH];
368 #endif
369 
370  /* load default values */
371  status = config_defaults(config);
372  if (status) {
373  eprintf("config_defaults() failed with %d\n", status);
374  goto out;
375  }
376 
377 #ifdef __REACTOS__
378  if (GetSystemDirectoryA(config_path, ARRAYSIZE(config_path)))
379  {
380  StringCchCatA(config_path, ARRAYSIZE(config_path), "\\drivers\\etc\\ms-nfs41-idmap.conf");
381  }
382  else
383  {
384  StringCchCopyA(config_path, ARRAYSIZE(config_path), "C:\\ReactOS\\system32\\drivers\\etc\\ms-nfs41-idmap.conf");
385  }
386 #endif
387 
388  /* load configuration from file */
389 #ifdef __REACTOS__
390  status = config_load(config, config_path);
391 #else
392  status = config_load(config, CONFIG_FILENAME);
393 #endif
394  if (status) {
395 #ifdef __REACTOS__
396  eprintf("config_load('%s') failed with %d\n", config_path, status);
397 #else
398  eprintf("config_load('%s') failed with %d\n", CONFIG_FILENAME, status);
399 #endif
400  goto out;
401  }
402 out:
403  return status;
404 }
405 
406 
407 /* generic cache */
408 typedef struct list_entry* (*entry_alloc_fn)();
409 typedef void (*entry_free_fn)(struct list_entry*);
410 typedef void (*entry_copy_fn)(struct list_entry*, const struct list_entry*);
411 
412 struct cache_ops {
416 };
417 
418 struct idmap_cache {
419  struct list_entry head;
420  const struct cache_ops *ops;
421  SRWLOCK lock;
422 };
423 
424 
425 static void cache_init(
426  struct idmap_cache *cache,
427  const struct cache_ops *ops)
428 {
429  list_init(&cache->head);
430  cache->ops = ops;
431  InitializeSRWLock(&cache->lock);
432 }
433 
434 static void cache_cleanup(
435  struct idmap_cache *cache)
436 {
437  struct list_entry *entry, *tmp;
438  list_for_each_tmp(entry, tmp, &cache->head)
439  cache->ops->entry_free(entry);
440  list_init(&cache->head);
441 }
442 
443 static int cache_insert(
444  struct idmap_cache *cache,
445  const struct idmap_lookup *lookup,
446  const struct list_entry *src)
447 {
448  struct list_entry *entry;
449  int status = NO_ERROR;
450 
451  AcquireSRWLockExclusive(&cache->lock);
452 
453  /* search for an existing match */
454  entry = list_search(&cache->head, lookup->value, lookup->compare);
455  if (entry) {
456  /* overwrite the existing entry with the new results */
457  cache->ops->entry_copy(entry, src);
458  goto out;
459  }
460 
461  /* initialize a new entry and add it to the list */
462  entry = cache->ops->entry_alloc();
463  if (entry == NULL) {
464  status = GetLastError();
465  goto out;
466  }
467  cache->ops->entry_copy(entry, src);
468  list_add_head(&cache->head, entry);
469 out:
470  ReleaseSRWLockExclusive(&cache->lock);
471  return status;
472 }
473 
474 static int cache_lookup(
475  struct idmap_cache *cache,
476  const struct idmap_lookup *lookup,
477  struct list_entry *entry_out)
478 {
479  struct list_entry *entry;
480  int status = ERROR_NOT_FOUND;
481 
482  AcquireSRWLockShared(&cache->lock);
483 
484  entry = list_search(&cache->head, lookup->value, lookup->compare);
485  if (entry) {
486  /* make a copy for use outside of the lock */
487  cache->ops->entry_copy(entry_out, entry);
488  status = NO_ERROR;
489  }
490 
491  ReleaseSRWLockShared(&cache->lock);
492  return status;
493 }
494 
495 
496 /* user cache */
497 struct idmap_user {
500  char principal[VAL_LEN];
504 };
505 
506 static struct list_entry* user_cache_alloc()
507 {
508  struct idmap_user *user = calloc(1, sizeof(struct idmap_user));
509  return user == NULL ? NULL : &user->entry;
510 }
511 static void user_cache_free(struct list_entry *entry)
512 {
513  free(list_container(entry, struct idmap_user, entry));
514 }
515 static void user_cache_copy(
516  struct list_entry *lhs,
517  const struct list_entry *rhs)
518 {
519  struct idmap_user *dst = list_container(lhs, struct idmap_user, entry);
520  const struct idmap_user *src = list_container(rhs, const struct idmap_user, entry);
523  dst->uid = src->uid;
524  dst->gid = src->gid;
525  dst->last_updated = src->last_updated;
526 }
527 static const struct cache_ops user_cache_ops = {
531 };
532 
533 
534 /* group cache */
535 struct idmap_group {
537  char name[VAL_LEN];
540 };
541 
543 {
544  struct idmap_group *group = calloc(1, sizeof(struct idmap_group));
545  return group == NULL ? NULL : &group->entry;
546 }
547 static void group_cache_free(struct list_entry *entry)
548 {
549  free(list_container(entry, struct idmap_group, entry));
550 }
551 static void group_cache_copy(
552  struct list_entry *lhs,
553  const struct list_entry *rhs)
554 {
555  struct idmap_group *dst = list_container(lhs, struct idmap_group, entry);
556  const struct idmap_group *src = list_container(rhs, const struct idmap_group, entry);
557  StringCchCopyA(dst->name, VAL_LEN, src->name);
558  dst->gid = src->gid;
559  dst->last_updated = src->last_updated;
560 }
561 static const struct cache_ops group_cache_ops = {
565 };
566 
567 
568 /* ldap context */
571  struct idmap_cache users;
574 };
575 
576 
577 static int idmap_filter(
578  struct idmap_config *config,
579  const struct idmap_lookup *lookup,
580  char *filter,
581  size_t filter_len)
582 {
583  UINT_PTR i;
584  int status = NO_ERROR;
585 
586  switch (lookup->type) {
587  case TYPE_INT:
588  i = (UINT_PTR)lookup->value;
589  if (FAILED(StringCchPrintfA(filter, filter_len,
590  "(&(objectClass=%s)(%s=%u))",
591  config->classes[lookup->klass],
592  config->attributes[lookup->attr], (UINT)i))) {
593  status = ERROR_BUFFER_OVERFLOW;
594  eprintf("ldap filter buffer overflow: '%s=%u'\n",
595  config->attributes[lookup->attr], (UINT)i);
596  }
597  break;
598 
599  case TYPE_STR:
600  if (FAILED(StringCchPrintfA(filter, filter_len,
601  "(&(objectClass=%s)(%s=%s))",
602  config->classes[lookup->klass],
603  config->attributes[lookup->attr], lookup->value))) {
604  status = ERROR_BUFFER_OVERFLOW;
605  eprintf("ldap filter buffer overflow: '%s=%s'\n",
606  config->attributes[lookup->attr], lookup->value);
607  }
608  break;
609 
610  default:
611  status = ERROR_INVALID_PARAMETER;
612  break;
613  }
614  return status;
615 }
616 
617 static int idmap_query_attrs(
618  struct idmap_context *context,
619  const struct idmap_lookup *lookup,
620  const unsigned attributes,
621  const unsigned optional,
622  PCHAR *values[],
623  const int len)
624 {
625  char filter[FILTER_LEN];
626  struct idmap_config *config = &context->config;
627  LDAPMessage *res = NULL, *entry;
628  int i, status;
629 
630  /* format the ldap filter */
631  status = idmap_filter(config, lookup, filter, FILTER_LEN);
632  if (status)
633  goto out;
634 
635  /* send the ldap query */
636  status = ldap_search_st(context->ldap, config->base,
637  LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, &res);
638  if (status) {
639  eprintf("ldap search for '%s' failed with %d: %s\n",
640  filter, status, ldap_err2stringA(status));
641  status = LdapMapErrorToWin32(status);
642  goto out;
643  }
644 
645  entry = ldap_first_entry(context->ldap, res);
646  if (entry == NULL) {
647  status = LDAP_NO_RESULTS_RETURNED;
648  eprintf("ldap search for '%s' failed with %d: %s\n",
649  filter, status, ldap_err2stringA(status));
650  status = LdapMapErrorToWin32(status);
651  goto out;
652  }
653 
654  /* fetch the attributes */
655  for (i = 0; i < len; i++) {
656  if (ATTR_ISSET(attributes, i)) {
657  values[i] = ldap_get_values(context->ldap,
658  entry, config->attributes[i]);
659 
660  /* fail if required attributes are missing */
661  if (values[i] == NULL && !ATTR_ISSET(optional, i)) {
662  status = LDAP_NO_SUCH_ATTRIBUTE;
663  eprintf("ldap entry for '%s' missing required "
664  "attribute '%s', returning %d: %s\n",
665  filter, config->attributes[i],
666  status, ldap_err2stringA(status));
667  status = LdapMapErrorToWin32(status);
668  goto out;
669  }
670  }
671  }
672 out:
673  if (res) ldap_msgfree(res);
674  return status;
675 }
676 
677 static int idmap_lookup_user(
678  struct idmap_context *context,
679  const struct idmap_lookup *lookup,
680  struct idmap_user *user)
681 {
683  const unsigned attributes = ATTR_FLAG(ATTR_USER_NAME)
686  | ATTR_FLAG(ATTR_GID);
687  /* principal is optional; we'll cache it if we have it */
688  const unsigned optional = ATTR_FLAG(ATTR_PRINCIPAL);
689  int i, status;
690 
691  /* check the user cache for an existing entry */
692  status = cache_lookup(&context->users, lookup, &user->entry);
693  if (status == NO_ERROR) {
694  /* don't return expired entries; query new attributes
695  * and overwrite the entry with cache_insert() */
696  if (time(NULL) - user->last_updated < context->config.cache_ttl)
697  goto out;
698  }
699 
700  /* send the query to the ldap server */
701  status = idmap_query_attrs(context, lookup,
702  attributes, optional, values, NUM_ATTRIBUTES);
703  if (status)
704  goto out_free_values;
705 
706  /* parse attributes */
708  *values[ATTR_USER_NAME]))) {
709  eprintf("ldap attribute %s='%s' longer than %u characters\n",
710  context->config.attributes[ATTR_USER_NAME],
711  *values[ATTR_USER_NAME], VAL_LEN);
712  status = ERROR_BUFFER_OVERFLOW;
713  goto out_free_values;
714  }
716  values[ATTR_PRINCIPAL] ? *values[ATTR_PRINCIPAL] : ""))) {
717  eprintf("ldap attribute %s='%s' longer than %u characters\n",
718  context->config.attributes[ATTR_PRINCIPAL],
719  values[ATTR_PRINCIPAL] ? *values[ATTR_PRINCIPAL] : "", VAL_LEN);
720  status = ERROR_BUFFER_OVERFLOW;
721  goto out_free_values;
722  }
723  if (!parse_uint(*values[ATTR_UID], &user->uid)) {
724  eprintf("failed to parse ldap attribute %s='%s'\n",
725  context->config.attributes[ATTR_UID], *values[ATTR_UID]);
726  status = ERROR_INVALID_PARAMETER;
727  goto out_free_values;
728  }
729  if (!parse_uint(*values[ATTR_GID], &user->gid)) {
730  eprintf("failed to parse ldap attribute %s='%s'\n",
731  context->config.attributes[ATTR_GID], *values[ATTR_GID]);
732  status = ERROR_INVALID_PARAMETER;
733  goto out_free_values;
734  }
735  user->last_updated = time(NULL);
736 
737  if (context->config.cache_ttl) {
738  /* insert the entry into the cache */
739  cache_insert(&context->users, lookup, &user->entry);
740  }
741 out_free_values:
742  for (i = 0; i < NUM_ATTRIBUTES; i++)
743  ldap_value_free(values[i]);
744 out:
745  return status;
746 }
747 
749  struct idmap_context *context,
750  const struct idmap_lookup *lookup,
751  struct idmap_group *group)
752 {
754  const unsigned attributes = ATTR_FLAG(ATTR_GROUP_NAME)
755  | ATTR_FLAG(ATTR_GID);
756  int i, status;
757 
758  /* check the group cache for an existing entry */
759  status = cache_lookup(&context->groups, lookup, &group->entry);
760  if (status == NO_ERROR) {
761  /* don't return expired entries; query new attributes
762  * and overwrite the entry with cache_insert() */
763  if (time(NULL) - group->last_updated < context->config.cache_ttl)
764  goto out;
765  }
766 
767  /* send the query to the ldap server */
768  status = idmap_query_attrs(context, lookup,
769  attributes, 0, values, NUM_ATTRIBUTES);
770  if (status)
771  goto out_free_values;
772 
773  /* parse attributes */
774  if (FAILED(StringCchCopyA(group->name, VAL_LEN,
775  *values[ATTR_GROUP_NAME]))) {
776  eprintf("ldap attribute %s='%s' longer than %u characters\n",
777  context->config.attributes[ATTR_GROUP_NAME],
778  *values[ATTR_GROUP_NAME], VAL_LEN);
779  status = ERROR_BUFFER_OVERFLOW;
780  goto out_free_values;
781  }
782  if (!parse_uint(*values[ATTR_GID], &group->gid)) {
783  eprintf("failed to parse ldap attribute %s='%s'\n",
784  context->config.attributes[ATTR_GID], *values[ATTR_GID]);
785  status = ERROR_INVALID_PARAMETER;
786  goto out_free_values;
787  }
788  group->last_updated = time(NULL);
789 
790  if (context->config.cache_ttl) {
791  /* insert the entry into the cache */
792  cache_insert(&context->groups, lookup, &group->entry);
793  }
794 out_free_values:
795  for (i = 0; i < NUM_ATTRIBUTES; i++)
796  ldap_value_free(values[i]);
797 out:
798  return status;
799 }
800 
801 
802 /* public idmap interface */
804  struct idmap_context **context_out)
805 {
806  struct idmap_context *context;
807  int status = NO_ERROR;
808 
809  context = calloc(1, sizeof(struct idmap_context));
810  if (context == NULL) {
811  status = GetLastError();
812  goto out;
813  }
814 
815  /* initialize the caches */
816  cache_init(&context->users, &user_cache_ops);
817  cache_init(&context->groups, &group_cache_ops);
818 
819  /* load ldap configuration from file */
820  status = config_init(&context->config);
821  if (status) {
822  eprintf("config_init() failed with %d\n", status);
823  goto out_err_free;
824  }
825 
826  /* initialize ldap and configure options */
827  context->ldap = ldap_init(context->config.hostname, context->config.port);
828  if (context->ldap == NULL) {
829  status = LdapGetLastError();
830  eprintf("ldap_init(%s) failed with %d: %s\n",
831  context->config.hostname, status, ldap_err2stringA(status));
832  status = LdapMapErrorToWin32(status);
833  goto out_err_free;
834  }
835 
837  (void *)&context->config.version);
838  if (status != LDAP_SUCCESS) {
839  eprintf("ldap_set_option(version=%d) failed with %d\n",
840  context->config.version, status);
841  status = LdapMapErrorToWin32(status);
842  goto out_err_free;
843  }
844 
845  if (context->config.timeout) {
846  status = ldap_set_option(context->ldap, LDAP_OPT_TIMELIMIT,
847  (void *)&context->config.timeout);
848  if (status != LDAP_SUCCESS) {
849  eprintf("ldap_set_option(timeout=%d) failed with %d\n",
850  context->config.timeout, status);
851  status = LdapMapErrorToWin32(status);
852  goto out_err_free;
853  }
854  }
855 
856  *context_out = context;
857 out:
858  return status;
859 
860 out_err_free:
861  nfs41_idmap_free(context);
862  goto out;
863 }
864 
866  struct idmap_context *context)
867 {
868  /* clean up the connection */
869  if (context->ldap)
870  ldap_unbind(context->ldap);
871 
872  cache_cleanup(&context->users);
873  cache_cleanup(&context->groups);
874  free(context);
875 }
876 
877 
878 /* username -> uid, gid */
879 static int username_cmp(const struct list_entry *list, const void *value)
880 {
881  const struct idmap_user *entry = list_container(list,
882  const struct idmap_user, entry);
883  const char *username = (const char*)value;
884  return strcmp(entry->username, username);
885 }
886 
888  struct idmap_context *context,
889  const char *username,
890  uid_t *uid_out,
891  gid_t *gid_out)
892 {
893  struct idmap_lookup lookup = { ATTR_USER_NAME,
895  struct idmap_user user;
896  int status;
897 
898  if (context == NULL)
899  return ERROR_FILE_NOT_FOUND;
900 
901  dprintf(IDLVL, "--> nfs41_idmap_name_to_ids('%s')\n", username);
902 
903  lookup.value = username;
904 
905  /* look up the user entry */
906  status = idmap_lookup_user(context, &lookup, &user);
907  if (status) {
908  dprintf(IDLVL, "<-- nfs41_idmap_name_to_ids('%s') "
909  "failed with %d\n", username, status);
910  goto out;
911  }
912 
913  *uid_out = user.uid;
914  *gid_out = user.gid;
915  dprintf(IDLVL, "<-- nfs41_idmap_name_to_ids('%s') "
916  "returning uid=%u, gid=%u\n", username, user.uid, user.gid);
917 out:
918  return status;
919 }
920 
921 /* uid -> username */
922 static int uid_cmp(const struct list_entry *list, const void *value)
923 {
924  const struct idmap_user *entry = list_container(list,
925  const struct idmap_user, entry);
926  const UINT_PTR uid = (const UINT_PTR)value;
927  return (UINT)uid - entry->uid;
928 }
929 
931  struct idmap_context *context,
932  uid_t uid,
933  char *name,
934  size_t len)
935 {
936  UINT_PTR uidp = uid; /* convert to pointer size to pass as void* */
937  struct idmap_lookup lookup = { ATTR_UID, CLASS_USER, TYPE_INT, uid_cmp };
938  struct idmap_user user;
939  int status;
940 
941  dprintf(IDLVL, "--> nfs41_idmap_uid_to_name(%u)\n", uid);
942 
943  lookup.value = (const void*)uidp;
944 
945  /* look up the user entry */
946  status = idmap_lookup_user(context, &lookup, &user);
947  if (status) {
948  dprintf(IDLVL, "<-- nfs41_idmap_uid_to_name(%u) "
949  "failed with %d\n", uid, status);
950  goto out;
951  }
952 
953  if (FAILED(StringCchCopyA(name, len, user.username))) {
954  status = ERROR_BUFFER_OVERFLOW;
955  eprintf("username buffer overflow: '%s' > %u\n",
956  user.username, len);
957  goto out;
958  }
959 
960  dprintf(IDLVL, "<-- nfs41_idmap_uid_to_name(%u) "
961  "returning '%s'\n", uid, name);
962 out:
963  return status;
964 }
965 
966 /* principal -> uid, gid */
967 static int principal_cmp(const struct list_entry *list, const void *value)
968 {
969  const struct idmap_user *entry = list_container(list,
970  const struct idmap_user, entry);
971  const char *principal = (const char*)value;
972  return strcmp(entry->principal, principal);
973 }
974 
976  struct idmap_context *context,
977  const char *principal,
978  uid_t *uid_out,
979  gid_t *gid_out)
980 {
981  struct idmap_lookup lookup = { ATTR_PRINCIPAL,
983  struct idmap_user user;
984  int status;
985 
986  dprintf(IDLVL, "--> nfs41_idmap_principal_to_ids('%s')\n", principal);
987 
988  lookup.value = principal;
989 
990  /* look up the user entry */
991  status = idmap_lookup_user(context, &lookup, &user);
992  if (status) {
993  dprintf(IDLVL, "<-- nfs41_idmap_principal_to_ids('%s') "
994  "failed with %d\n", principal, status);
995  goto out;
996  }
997 
998  *uid_out = user.uid;
999  *gid_out = user.gid;
1000  dprintf(IDLVL, "<-- nfs41_idmap_principal_to_ids('%s') "
1001  "returning uid=%u, gid=%u\n", principal, user.uid, user.gid);
1002 out:
1003  return status;
1004 }
1005 
1006 /* group -> gid */
1007 static int group_cmp(const struct list_entry *list, const void *value)
1008 {
1009  const struct idmap_group *entry = list_container(list,
1010  const struct idmap_group, entry);
1011  const char *group = (const char*)value;
1012  return strcmp(entry->name, group);
1013 }
1014 
1016  struct idmap_context *context,
1017  const char *name,
1018  gid_t *gid_out)
1019 {
1020  struct idmap_lookup lookup = { ATTR_GROUP_NAME,
1022  struct idmap_group group;
1023  int status;
1024 
1025  dprintf(IDLVL, "--> nfs41_idmap_group_to_gid('%s')\n", name);
1026 
1027  lookup.value = name;
1028 
1029  /* look up the group entry */
1030  status = idmap_lookup_group(context, &lookup, &group);
1031  if (status) {
1032  dprintf(IDLVL, "<-- nfs41_idmap_group_to_gid('%s') "
1033  "failed with %d\n", name, status);
1034  goto out;
1035  }
1036 
1037  *gid_out = group.gid;
1038  dprintf(IDLVL, "<-- nfs41_idmap_group_to_gid('%s') "
1039  "returning %u\n", name, group.gid);
1040 out:
1041  return status;
1042 }
1043 
1044 /* gid -> group */
1045 static int gid_cmp(const struct list_entry *list, const void *value)
1046 {
1047  const struct idmap_group *entry = list_container(list,
1048  const struct idmap_group, entry);
1049  const UINT_PTR gid = (const UINT_PTR)value;
1050  return (UINT)gid - entry->gid;
1051 }
1052 
1054  struct idmap_context *context,
1055  gid_t gid,
1056  char *name,
1057  size_t len)
1058 {
1059  UINT_PTR gidp = gid; /* convert to pointer size to pass as void* */
1060  struct idmap_lookup lookup = { ATTR_GID, CLASS_GROUP, TYPE_INT, gid_cmp };
1061  struct idmap_group group;
1062  int status;
1063 
1064  dprintf(IDLVL, "--> nfs41_idmap_gid_to_group(%u)\n", gid);
1065 
1066  lookup.value = (const void*)gidp;
1067 
1068  /* look up the group entry */
1069  status = idmap_lookup_group(context, &lookup, &group);
1070  if (status) {
1071  dprintf(IDLVL, "<-- nfs41_idmap_gid_to_group(%u) "
1072  "failed with %d\n", gid, status);
1073  goto out;
1074  }
1075 
1076  if (FAILED(StringCchCopyA(name, len, group.name))) {
1077  status = ERROR_BUFFER_OVERFLOW;
1078  eprintf("group name buffer overflow: '%s' > %u\n",
1079  group.name, len);
1080  goto out;
1081  }
1082 
1083  dprintf(IDLVL, "<-- nfs41_idmap_gid_to_group(%u) "
1084  "returning '%s'\n", gid, name);
1085 out:
1086  return status;
1087 }
time_t last_updated
Definition: idmap.c:503
struct idmap_cache groups
Definition: idmap.c:572
signed char * PCHAR
Definition: retypes.h:7
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
Definition: cache.c:46
VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:54
unsigned __int3264 UINT_PTR
Definition: activex.cpp:275
struct list_entry head
Definition: idmap.c:419
#define isspace(c)
Definition: acclib.h:69
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
Definition: get.c:139
#define TRUE
Definition: types.h:120
static const struct cache_ops group_cache_ops
Definition: idmap.c:561
static int config_find_option(const struct config_pair *pair, const struct config_option **option)
Definition: idmap.c:275
char name[VAL_LEN]
Definition: idmap.c:537
#define OPT_ATTR(key, def, index)
Definition: idmap.c:119
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:47
int nfs41_idmap_group_to_gid(struct idmap_context *context, const char *name, gid_t *gid_out)
Definition: idmap.c:1015
WINLDAPAPI ULONG ldap_msgfree(LDAPMessage *)
LDAP * ldap
Definition: idmap.c:573
static struct list_entry * user_cache_alloc()
Definition: idmap.c:506
Definition: http.c:6587
struct outqueuenode * head
Definition: adnsresfilter.c:66
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
entry_copy_fn entry_copy
Definition: idmap.c:415
#define ERROR_BUFFER_OVERFLOW
Definition: winerror.h:185
uid_t uid
Definition: idmap.c:501
static int uid_cmp(const struct list_entry *list, const void *value)
Definition: idmap.c:922
GLuint GLuint GLsizei count
Definition: gl.h:1545
static int cache_lookup(struct idmap_cache *cache, const struct idmap_lookup *lookup, struct list_entry *entry_out)
Definition: idmap.c:474
#define free
Definition: debug_ros.c:5
Definition: idmap.c:53
uint8_t entry
Definition: isohybrid.c:63
#define ldap_get_values
Definition: winldap.h:670
static int idmap_filter(struct idmap_config *config, const struct idmap_lookup *lookup, char *filter, size_t filter_len)
Definition: idmap.c:577
#define ATTR_ISSET(mask, attr)
Definition: idmap.c:60
GLboolean GLenum GLenum GLvoid * values
Definition: glext.h:5666
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
WINLDAPAPI PLDAPMessage ldap_first_entry(LDAP *, LDAPMessage *)
UINT WINAPI GetSystemDirectoryA(OUT LPSTR lpBuffer, IN UINT uSize)
Definition: path.c:2282
WINLDAPAPI ULONG ldap_unbind(LDAP *)
size_t value_len
Definition: idmap.c:150
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
static ULONG lookup[16]
Definition: vga.c:46
GLuint buffer
Definition: glext.h:5915
void eprintf(LPCSTR format,...)
Definition: daemon_debug.c:86
int nfs41_idmap_name_to_ids(struct idmap_context *context, const char *username, uid_t *uid_out, gid_t *gid_out)
Definition: idmap.c:887
gid_t gid
Definition: idmap.c:502
Definition: dhcpd.h:245
const char * key
Definition: idmap.c:105
PCHAR CDECL ldap_err2stringA(ULONG err)
Definition: error.c:71
int errno
__u16 time
Definition: mkdosfs.c:366
struct idmap_cache users
Definition: idmap.c:571
const char * filename
Definition: ioapi.h:135
#define NO_ERROR
Definition: dderror.h:5
size_t offset
Definition: idmap.c:108
long uid_t
Definition: various.h:8
int32_t INT
Definition: typedefs.h:56
static int idmap_lookup_user(struct idmap_context *context, const struct idmap_lookup *lookup, struct idmap_user *user)
Definition: idmap.c:677
static int principal_cmp(const struct list_entry *list, const void *value)
Definition: idmap.c:967
#define LDAP_OPT_PROTOCOL_VERSION
Definition: winldap.h:145
ldap_class
Definition: idmap.c:42
#define LDAP_OPT_TIMELIMIT
Definition: winldap.h:133
#define OPT_INT(key, def, field)
Definition: idmap.c:113
gid_t gid
Definition: idmap.c:538
size_t key_len
Definition: idmap.c:150
char * hostname
Definition: ftp.c:88
char base[VAL_LEN]
Definition: idmap.c:92
GLuint const GLubyte GLvoid * src
Definition: s_context.h:57
int nfs41_idmap_principal_to_ids(struct idmap_context *context, const char *principal, uid_t *uid_out, gid_t *gid_out)
Definition: idmap.c:975
GLenum GLclampf GLint i
Definition: glfuncs.h:14
ULONG CDECL LdapMapErrorToWin32(ULONG err)
Definition: error.c:302
static int idmap_query_attrs(struct idmap_context *context, const struct idmap_lookup *lookup, const unsigned attributes, const unsigned optional, PCHAR *values[], const int len)
Definition: idmap.c:617
STRSAFEAPI StringCchCopyNA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:230
enum ldap_class klass
Definition: idmap.c:66
list_compare_fn compare
Definition: idmap.c:72
GLsizei GLuint * groups
Definition: glext.h:11113
static int username_cmp(const struct list_entry *list, const void *value)
Definition: idmap.c:879
#define ldap_value_free
Definition: winldap.h:689
UINT gid_t
Definition: types.h:89
STRSAFEAPI StringCchCatA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:320
#define NFS41_HOSTNAME_LEN
Definition: nfs41_const.h:48
#define dprintf
Definition: regdump.c:33
#define ldap_search_st
Definition: winldap.h:680
time_t last_updated
Definition: idmap.c:539
static void user_cache_free(struct list_entry *entry)
Definition: idmap.c:511
STRSAFEAPI StringCchPrintfA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszFormat,...)
Definition: strsafe.h:520
enum ldap_attr attr
Definition: idmap.c:65
UINT timeout
Definition: idmap.c:87
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:416
static const WCHAR version[]
Definition: asmname.c:64
Definition: getopt.h:108
static int group_cmp(const struct list_entry *list, const void *value)
Definition: idmap.c:1007
Definition: parser.c:48
static void cache_cleanup(struct idmap_cache *cache)
Definition: idmap.c:434
entry_alloc_fn entry_alloc
Definition: idmap.c:413
enum config_type type
Definition: idmap.c:70
static void group_cache_free(struct list_entry *entry)
Definition: idmap.c:547
#define list_container(entry, type, field)
Definition: list.h:33
int nfs41_idmap_uid_to_name(struct idmap_context *context, uid_t uid, char *name, size_t len)
Definition: idmap.c:930
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
ldap_attr
Definition: idmap.c:49
Definition: msg.h:41
static BOOL parse_uint(const char *str, UINT *id_out)
Definition: idmap.c:223
GLuint GLenum option
Definition: glext.h:11211
_Check_return_ _CRTIMP int __cdecl stricmp(_In_z_ const char *_Str1, _In_z_ const char *_Str2)
#define LDAP_NO_RESULTS_RETURNED
Definition: winldap.h:114
static WCHAR username[]
Definition: url.c:32
char attributes[NUM_ATTRIBUTES][NAME_LEN]
Definition: idmap.c:91
#define IDLVL
Definition: idmap.c:35
static void group_cache_copy(struct list_entry *lhs, const struct list_entry *rhs)
Definition: idmap.c:551
char classes[NUM_CLASSES][NAME_LEN]
Definition: idmap.c:90
GLboolean GLuint group
Definition: glext.h:11120
const char * value
Definition: idmap.c:149
static const struct cache_ops user_cache_ops
Definition: idmap.c:527
char username[VAL_LEN]
Definition: idmap.c:499
unsigned int BOOL
Definition: ntddk_ex.h:94
struct list_entry entry
Definition: idmap.c:498
enum config_type type
Definition: idmap.c:107
if(!(yy_init))
Definition: macro.lex.yy.c:717
static int config_defaults(struct idmap_config *config)
Definition: idmap.c:243
const char * def
Definition: idmap.c:106
#define MAX_PATH
Definition: compat.h:26
const char file[]
Definition: icontest.c:11
unsigned int UINT
Definition: ndis.h:50
static int idmap_lookup_group(struct idmap_context *context, const struct idmap_lookup *lookup, struct idmap_group *group)
Definition: idmap.c:748
const char * key
Definition: idmap.c:149
static FILE * out
Definition: regtests2xml.c:44
struct list_entry *(* entry_alloc_fn)()
Definition: idmap.c:408
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
config_type
Definition: idmap.c:99
#define ERANGE
Definition: acclib.h:92
#define ATTR_FLAG(attr)
Definition: idmap.c:59
struct idmap_config config
Definition: idmap.c:570
const struct cache_ops * ops
Definition: idmap.c:420
char line[200]
Definition: main.c:97
entry_free_fn entry_free
Definition: idmap.c:414
int(* list_compare_fn)(const struct list_entry *, const void *)
Definition: list.h:100
#define LDAP_NO_SUCH_ATTRIBUTE
Definition: winldap.h:74
HKEY key
Definition: reg.c:42
VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK Lock)
Definition: sync.c:82
SRWLOCK lock
Definition: idmap.c:421
GLenum GLsizei len
Definition: glext.h:6722
Definition: _list.h:228
struct list_entry entry
Definition: idmap.c:536
char principal[VAL_LEN]
Definition: idmap.c:500
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
#define VAL_LEN
Definition: idmap.c:39
VOID WINAPI InitializeSRWLock(PSRWLOCK Lock)
Definition: sync.c:75
#define FILTER_LEN
Definition: idmap.c:37
#define ldap_init
Definition: winldap.h:638
void(* entry_copy_fn)(struct list_entry *, const struct list_entry *)
Definition: idmap.c:410
static int gid_cmp(const struct list_entry *list, const void *value)
Definition: idmap.c:1045
#define LDAP_SCOPE_SUBTREE
Definition: winldap.h:190
#define OPT_STR(key, def, field, len)
Definition: idmap.c:115
static struct list_entry * list_search(const struct list_entry *head, const void *value, list_compare_fn compare)
Definition: list.h:102
static int cache_insert(struct idmap_cache *cache, const struct idmap_lookup *lookup, const struct list_entry *src)
Definition: idmap.c:443
STRSAFEAPI StringCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:145
size_t max_len
Definition: idmap.c:109
_Check_return_opt_ _CRTIMP char *__cdecl fgets(_Out_writes_z_(_MaxCount) char *_Buf, _In_ int _MaxCount, _Inout_ FILE *_File)
ULONG CDECL LdapGetLastError(void)
Definition: error.c:184
static int config_load(struct idmap_config *config, const char *filename)
Definition: idmap.c:293
__kernel_time_t time_t
Definition: linux.h:252
INT cache_ttl
Definition: idmap.c:95
Definition: _pair.h:47
Definition: list.h:27
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
GLuint const GLubyte GLvoid const GLvoid * dst
Definition: s_context.h:57
#define ERROR_NOT_FOUND
Definition: winerror.h:690
static const char CONFIG_FILENAME[]
Definition: idmap.c:79
UINT32 uint32_t
Definition: types.h:75
char * strchr(const char *String, int ch)
Definition: utclib.c:501
static const struct config_option g_options[]
Definition: idmap.c:123
#define LDAP_SUCCESS
Definition: winldap.h:59
int nfs41_idmap_gid_to_group(struct idmap_context *context, gid_t gid, char *name, size_t len)
Definition: idmap.c:1053
static void user_cache_copy(struct list_entry *lhs, const struct list_entry *rhs)
Definition: idmap.c:515
static int config_init(struct idmap_config *config)
Definition: idmap.c:362
Definition: name.c:36
#define list_for_each_tmp(entry, tmp, head)
Definition: list.h:39
#define calloc
Definition: rosglue.h:14
GLuint res
Definition: glext.h:9613
Definition: idmap.c:54
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
GLenum GLuint id
Definition: glext.h:5579
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
UINT version
Definition: idmap.c:86
static struct list_entry * group_cache_alloc()
Definition: idmap.c:542
int nfs41_idmap_create(struct idmap_context **context_out)
Definition: idmap.c:803
#define OPT_CLASS(key, def, index)
Definition: idmap.c:117
const void * value
Definition: idmap.c:73
USHORT port
Definition: uri.c:227
#define ldap_set_option
Definition: winldap.h:641
static void cache_init(struct idmap_cache *cache, const struct cache_ops *ops)
Definition: idmap.c:425
static SERVICE_STATUS status
Definition: service.c:31
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
void user(int argc, const char *argv[])
Definition: cmds.c:1350
UINT port
Definition: idmap.c:85
void nfs41_idmap_free(struct idmap_context *context)
Definition: idmap.c:865
VOID WINAPI AcquireSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:61
VOID WINAPI ReleaseSRWLockShared(PSRWLOCK Lock)
Definition: sync.c:89
void(* entry_free_fn)(struct list_entry *)
Definition: idmap.c:409
#define ULONG_MAX
Definition: limits.h:44
static int config_parse_pair(char *line, struct config_pair *pair)
Definition: idmap.c:153
#define NAME_LEN
Definition: idmap.c:38
Definition: ps.c:97
GLuint const GLchar * name
Definition: glext.h:6031