1 /* NFSv4.1 client for Windows
2 * Copyright © 2012 The Regents of the University of Michigan
4 * Olga Kornievskaia <aglo@umich.edu>
5 * Casey Bodley <cbodley@umich.edu>
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.
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.
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
25 #include <stdlib.h> /* for strtoul() */
30 #include "nfs41_const.h"
32 #include "daemon_debug.h"
35 #define IDLVL 2 /* dprintf level for idmap logging */
37 #define FILTER_LEN 1024
59 #define ATTR_FLAG(attr) (1 << (attr))
60 #define ATTR_ISSET(mask, attr) (((mask) & ATTR_FLAG(attr)) != 0)
63 /* ldap/cache lookups */
66 enum ldap_class klass
;
70 enum config_type type
;
72 list_compare_fn compare
;
78 static const char CONFIG_FILENAME
[] = "C:\\ReactOS\\System32\\drivers\\etc\\ms-nfs41-idmap.conf";
81 /* ldap server information */
82 char hostname
[NFS41_HOSTNAME_LEN
+1];
87 /* ldap schema information */
88 char classes
[NUM_CLASSES
][NAME_LEN
];
89 char attributes
[NUM_ATTRIBUTES
][NAME_LEN
];
92 /* caching configuration */
102 struct config_option
{
105 enum config_type type
;
110 /* helper macros for declaring config_options */
111 #define OPT_INT(key,def,field) \
112 { key, def, TYPE_INT, FIELD_OFFSET(struct idmap_config, field), 0 }
113 #define OPT_STR(key,def,field,len) \
114 { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, field), len }
115 #define OPT_CLASS(key,def,index) \
116 { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, classes[index]), NAME_LEN }
117 #define OPT_ATTR(key,def,index) \
118 { key, def, TYPE_STR, FIELD_OFFSET(struct idmap_config, attributes[index]), NAME_LEN }
120 /* table of recognized config options, including type and default value */
121 static const struct config_option g_options
[] = {
122 /* server information */
123 OPT_STR("ldap_hostname", "localhost", hostname
, NFS41_HOSTNAME_LEN
+1),
124 OPT_INT("ldap_port", "389", port
),
125 OPT_INT("ldap_version", "3", version
),
126 OPT_INT("ldap_timeout", "0", timeout
),
128 /* schema information */
129 OPT_STR("ldap_base", "cn=localhost", base
, VAL_LEN
),
130 OPT_CLASS("ldap_class_users", "user", CLASS_USER
),
131 OPT_CLASS("ldap_class_groups", "group", CLASS_GROUP
),
132 OPT_ATTR("ldap_attr_username", "cn", ATTR_USER_NAME
),
133 OPT_ATTR("ldap_attr_groupname", "cn", ATTR_GROUP_NAME
),
134 OPT_ATTR("ldap_attr_gssAuthName", "gssAuthName", ATTR_PRINCIPAL
),
135 OPT_ATTR("ldap_attr_uidNumber", "uidNumber", ATTR_UID
),
136 OPT_ATTR("ldap_attr_gidNumber", "gidNumber", ATTR_GID
),
138 /* caching configuration */
139 OPT_INT("cache_ttl", "60", cache_ttl
),
143 /* parse each line into key-value pairs
144 * accepts 'key = value' or 'key = "value"',
145 * ignores whitespace anywhere outside the ""s */
147 const char *key
, *value
;
148 size_t key_len
, value_len
;
151 static int config_parse_pair(
153 struct config_pair
*pair
)
156 int status
= NO_ERROR
;
158 /* terminate at comment */
159 pos
= strchr(line
, '#');
162 /* skip whitespace before key */
164 while (isspace(*pos
)) pos
++;
167 pos
= strchr(pos
, '=');
169 eprintf("missing '='\n");
170 status
= ERROR_INVALID_PARAMETER
;
174 /* skip whitespace after key */
175 pair
->key_len
= pos
- pair
->key
;
176 while (pair
->key_len
&& isspace(pair
->key
[pair
->key_len
-1]))
179 if (pair
->key_len
<= 0) {
180 eprintf("empty key\n");
181 status
= ERROR_INVALID_PARAMETER
;
185 /* skip whitespace after = */
187 while (isspace(*pos
)) pos
++;
190 eprintf("end of line looking for value\n");
191 status
= ERROR_INVALID_PARAMETER
;
196 /* value is between the "s */
197 pair
->value
= pos
+ 1;
198 pos
= strchr(pair
->value
, '\"');
200 eprintf("no matching '\"'\n");
201 status
= ERROR_INVALID_PARAMETER
;
204 pair
->value_len
= pos
- pair
->value
;
207 pair
->value_len
= strlen(pair
->value
);
209 /* skip whitespace after value */
210 while (pair
->value_len
&& isspace(pair
->value
[pair
->value_len
-1]))
214 /* on success, null terminate the key and value */
215 ((char*)pair
->key
)[pair
->key_len
] = 0;
216 ((char*)pair
->value
)[pair
->value_len
] = 0;
221 static BOOL
parse_uint(
226 const UINT id
= strtoul(str
, &endp
, 10);
228 /* must convert the whole string */
229 if ((endp
- str
) < (ptrdiff_t)strlen(str
))
232 /* result must fit in 32 bits */
233 if (id
== ULONG_MAX
&& errno
== ERANGE
)
240 /* parse default values from g_options[] into idmap_config */
241 static int config_defaults(
242 struct idmap_config
*config
)
244 const struct config_option
*option
;
245 const int count
= ARRAYSIZE(g_options
);
247 int i
, status
= NO_ERROR
;
249 for (i
= 0; i
< count
; i
++) {
250 option
= &g_options
[i
];
251 dst
= (char*)config
+ option
->offset
;
253 if (option
->type
== TYPE_INT
) {
254 if (!parse_uint(option
->def
, (UINT
*)dst
)) {
255 status
= ERROR_INVALID_PARAMETER
;
256 eprintf("failed to parse default value of %s=\"%s\": "
257 "expected a number\n", option
->key
, option
->def
);
261 if (FAILED(StringCchCopyA(dst
, option
->max_len
, option
->def
))) {
262 status
= ERROR_BUFFER_OVERFLOW
;
263 eprintf("failed to parse default value of %s=\"%s\": "
264 "buffer overflow > %u\n", option
->key
, option
->def
,
273 static int config_find_option(
274 const struct config_pair
*pair
,
275 const struct config_option
**option
)
277 int i
, count
= ARRAYSIZE(g_options
);
278 int status
= ERROR_NOT_FOUND
;
280 /* find the config_option by key */
281 for (i
= 0; i
< count
; i
++) {
282 if (stricmp(pair
->key
, g_options
[i
].key
) == 0) {
283 *option
= &g_options
[i
];
291 static int config_load(
292 struct idmap_config
*config
,
293 const char *filename
)
295 char buffer
[1024], *pos
;
297 struct config_pair pair
;
298 const struct config_option
*option
;
300 int status
= NO_ERROR
;
303 file
= fopen(filename
, "r");
305 eprintf("config_load() failed to open file '%s'\n", filename
);
310 while (fgets(buffer
, sizeof(buffer
), file
)) {
313 /* skip whitespace */
315 while (isspace(*pos
)) pos
++;
317 /* skip comments and empty lines */
318 if (*pos
== '#' || *pos
== 0)
321 /* parse line into a key=value pair */
322 status
= config_parse_pair(buffer
, &pair
);
324 eprintf("error on line %d: %s\n", line
, buffer
);
328 /* find the config_option by key */
329 status
= config_find_option(&pair
, &option
);
331 eprintf("unrecognized option '%s' on line %d: %s\n",
332 pair
.key
, line
, buffer
);
333 status
= ERROR_INVALID_PARAMETER
;
337 if (option
->type
== TYPE_INT
) {
338 if (!parse_uint(pair
.value
, (UINT
*)((char*)config
+ option
->offset
))) {
339 status
= ERROR_INVALID_PARAMETER
;
340 eprintf("expected a number on line %d: %s=\"%s\"\n",
341 line
, pair
.key
, pair
.value
);
345 if (FAILED(StringCchCopyNA((char*)config
+ option
->offset
,
346 option
->max_len
, pair
.value
, pair
.value_len
))) {
347 status
= ERROR_BUFFER_OVERFLOW
;
348 eprintf("overflow on line %d: %s=\"%s\"\n",
349 line
, pair
.key
, pair
.value
);
360 static int config_init(
361 struct idmap_config
*config
)
365 /* load default values */
366 status
= config_defaults(config
);
368 eprintf("config_defaults() failed with %d\n", status
);
372 /* load configuration from file */
373 status
= config_load(config
, CONFIG_FILENAME
);
375 eprintf("config_load('%s') failed with %d\n", CONFIG_FILENAME
, status
);
384 typedef struct list_entry
* (*entry_alloc_fn
)();
385 typedef void (*entry_free_fn
)(struct list_entry
*);
386 typedef void (*entry_copy_fn
)(struct list_entry
*, const struct list_entry
*);
389 entry_alloc_fn entry_alloc
;
390 entry_free_fn entry_free
;
391 entry_copy_fn entry_copy
;
395 struct list_entry head
;
396 const struct cache_ops
*ops
;
401 static void cache_init(
402 struct idmap_cache
*cache
,
403 const struct cache_ops
*ops
)
405 list_init(&cache
->head
);
407 InitializeSRWLock(&cache
->lock
);
410 static void cache_cleanup(
411 struct idmap_cache
*cache
)
413 struct list_entry
*entry
, *tmp
;
414 list_for_each_tmp(entry
, tmp
, &cache
->head
)
415 cache
->ops
->entry_free(entry
);
416 list_init(&cache
->head
);
419 static int cache_insert(
420 struct idmap_cache
*cache
,
421 const struct idmap_lookup
*lookup
,
422 const struct list_entry
*src
)
424 struct list_entry
*entry
;
425 int status
= NO_ERROR
;
427 AcquireSRWLockExclusive(&cache
->lock
);
429 /* search for an existing match */
430 entry
= list_search(&cache
->head
, lookup
->value
, lookup
->compare
);
432 /* overwrite the existing entry with the new results */
433 cache
->ops
->entry_copy(entry
, src
);
437 /* initialize a new entry and add it to the list */
438 entry
= cache
->ops
->entry_alloc();
440 status
= GetLastError();
443 cache
->ops
->entry_copy(entry
, src
);
444 list_add_head(&cache
->head
, entry
);
446 ReleaseSRWLockExclusive(&cache
->lock
);
450 static int cache_lookup(
451 struct idmap_cache
*cache
,
452 const struct idmap_lookup
*lookup
,
453 struct list_entry
*entry_out
)
455 struct list_entry
*entry
;
456 int status
= ERROR_NOT_FOUND
;
458 AcquireSRWLockShared(&cache
->lock
);
460 entry
= list_search(&cache
->head
, lookup
->value
, lookup
->compare
);
462 /* make a copy for use outside of the lock */
463 cache
->ops
->entry_copy(entry_out
, entry
);
467 ReleaseSRWLockShared(&cache
->lock
);
474 struct list_entry entry
;
475 char username
[VAL_LEN
];
476 char principal
[VAL_LEN
];
482 static struct list_entry
* user_cache_alloc()
484 struct idmap_user
*user
= calloc(1, sizeof(struct idmap_user
));
485 return user
== NULL
? NULL
: &user
->entry
;
487 static void user_cache_free(struct list_entry
*entry
)
489 free(list_container(entry
, struct idmap_user
, entry
));
491 static void user_cache_copy(
492 struct list_entry
*lhs
,
493 const struct list_entry
*rhs
)
495 struct idmap_user
*dst
= list_container(lhs
, struct idmap_user
, entry
);
496 const struct idmap_user
*src
= list_container(rhs
, const struct idmap_user
, entry
);
497 StringCchCopyA(dst
->username
, VAL_LEN
, src
->username
);
498 StringCchCopyA(dst
->principal
, VAL_LEN
, src
->principal
);
501 dst
->last_updated
= src
->last_updated
;
503 static const struct cache_ops user_cache_ops
= {
512 struct list_entry entry
;
518 static struct list_entry
* group_cache_alloc()
520 struct idmap_group
*group
= calloc(1, sizeof(struct idmap_group
));
521 return group
== NULL
? NULL
: &group
->entry
;
523 static void group_cache_free(struct list_entry
*entry
)
525 free(list_container(entry
, struct idmap_group
, entry
));
527 static void group_cache_copy(
528 struct list_entry
*lhs
,
529 const struct list_entry
*rhs
)
531 struct idmap_group
*dst
= list_container(lhs
, struct idmap_group
, entry
);
532 const struct idmap_group
*src
= list_container(rhs
, const struct idmap_group
, entry
);
533 StringCchCopyA(dst
->name
, VAL_LEN
, src
->name
);
535 dst
->last_updated
= src
->last_updated
;
537 static const struct cache_ops group_cache_ops
= {
545 struct idmap_context
{
546 struct idmap_config config
;
547 struct idmap_cache users
;
548 struct idmap_cache groups
;
553 static int idmap_filter(
554 struct idmap_config
*config
,
555 const struct idmap_lookup
*lookup
,
560 int status
= NO_ERROR
;
562 switch (lookup
->type
) {
564 i
= (UINT_PTR
)lookup
->value
;
565 if (FAILED(StringCchPrintfA(filter
, filter_len
,
566 "(&(objectClass=%s)(%s=%u))",
567 config
->classes
[lookup
->klass
],
568 config
->attributes
[lookup
->attr
], (UINT
)i
))) {
569 status
= ERROR_BUFFER_OVERFLOW
;
570 eprintf("ldap filter buffer overflow: '%s=%u'\n",
571 config
->attributes
[lookup
->attr
], (UINT
)i
);
576 if (FAILED(StringCchPrintfA(filter
, filter_len
,
577 "(&(objectClass=%s)(%s=%s))",
578 config
->classes
[lookup
->klass
],
579 config
->attributes
[lookup
->attr
], lookup
->value
))) {
580 status
= ERROR_BUFFER_OVERFLOW
;
581 eprintf("ldap filter buffer overflow: '%s=%s'\n",
582 config
->attributes
[lookup
->attr
], lookup
->value
);
587 status
= ERROR_INVALID_PARAMETER
;
593 static int idmap_query_attrs(
594 struct idmap_context
*context
,
595 const struct idmap_lookup
*lookup
,
596 const unsigned attributes
,
597 const unsigned optional
,
601 char filter
[FILTER_LEN
];
602 struct idmap_config
*config
= &context
->config
;
603 LDAPMessage
*res
= NULL
, *entry
;
606 /* format the ldap filter */
607 status
= idmap_filter(config
, lookup
, filter
, FILTER_LEN
);
611 /* send the ldap query */
612 status
= ldap_search_st(context
->ldap
, config
->base
,
613 LDAP_SCOPE_SUBTREE
, filter
, NULL
, 0, NULL
, &res
);
615 eprintf("ldap search for '%s' failed with %d: %s\n",
616 filter
, status
, ldap_err2stringA(status
));
617 status
= LdapMapErrorToWin32(status
);
621 entry
= ldap_first_entry(context
->ldap
, res
);
623 status
= LDAP_NO_RESULTS_RETURNED
;
624 eprintf("ldap search for '%s' failed with %d: %s\n",
625 filter
, status
, ldap_err2stringA(status
));
626 status
= LdapMapErrorToWin32(status
);
630 /* fetch the attributes */
631 for (i
= 0; i
< len
; i
++) {
632 if (ATTR_ISSET(attributes
, i
)) {
633 values
[i
] = ldap_get_values(context
->ldap
,
634 entry
, config
->attributes
[i
]);
636 /* fail if required attributes are missing */
637 if (values
[i
] == NULL
&& !ATTR_ISSET(optional
, i
)) {
638 status
= LDAP_NO_SUCH_ATTRIBUTE
;
639 eprintf("ldap entry for '%s' missing required "
640 "attribute '%s', returning %d: %s\n",
641 filter
, config
->attributes
[i
],
642 status
, ldap_err2stringA(status
));
643 status
= LdapMapErrorToWin32(status
);
649 if (res
) ldap_msgfree(res
);
653 static int idmap_lookup_user(
654 struct idmap_context
*context
,
655 const struct idmap_lookup
*lookup
,
656 struct idmap_user
*user
)
658 PCHAR
* values
[NUM_ATTRIBUTES
] = { NULL
};
659 const unsigned attributes
= ATTR_FLAG(ATTR_USER_NAME
)
660 | ATTR_FLAG(ATTR_PRINCIPAL
)
661 | ATTR_FLAG(ATTR_UID
)
662 | ATTR_FLAG(ATTR_GID
);
663 /* principal is optional; we'll cache it if we have it */
664 const unsigned optional
= ATTR_FLAG(ATTR_PRINCIPAL
);
667 /* check the user cache for an existing entry */
668 status
= cache_lookup(&context
->users
, lookup
, &user
->entry
);
669 if (status
== NO_ERROR
) {
670 /* don't return expired entries; query new attributes
671 * and overwrite the entry with cache_insert() */
672 if (time(NULL
) - user
->last_updated
< context
->config
.cache_ttl
)
676 /* send the query to the ldap server */
677 status
= idmap_query_attrs(context
, lookup
,
678 attributes
, optional
, values
, NUM_ATTRIBUTES
);
680 goto out_free_values
;
682 /* parse attributes */
683 if (FAILED(StringCchCopyA(user
->username
, VAL_LEN
,
684 *values
[ATTR_USER_NAME
]))) {
685 eprintf("ldap attribute %s='%s' longer than %u characters\n",
686 context
->config
.attributes
[ATTR_USER_NAME
],
687 *values
[ATTR_USER_NAME
], VAL_LEN
);
688 status
= ERROR_BUFFER_OVERFLOW
;
689 goto out_free_values
;
691 if (FAILED(StringCchCopyA(user
->principal
, VAL_LEN
,
692 values
[ATTR_PRINCIPAL
] ? *values
[ATTR_PRINCIPAL
] : ""))) {
693 eprintf("ldap attribute %s='%s' longer than %u characters\n",
694 context
->config
.attributes
[ATTR_PRINCIPAL
],
695 values
[ATTR_PRINCIPAL
] ? *values
[ATTR_PRINCIPAL
] : "", VAL_LEN
);
696 status
= ERROR_BUFFER_OVERFLOW
;
697 goto out_free_values
;
699 if (!parse_uint(*values
[ATTR_UID
], &user
->uid
)) {
700 eprintf("failed to parse ldap attribute %s='%s'\n",
701 context
->config
.attributes
[ATTR_UID
], *values
[ATTR_UID
]);
702 status
= ERROR_INVALID_PARAMETER
;
703 goto out_free_values
;
705 if (!parse_uint(*values
[ATTR_GID
], &user
->gid
)) {
706 eprintf("failed to parse ldap attribute %s='%s'\n",
707 context
->config
.attributes
[ATTR_GID
], *values
[ATTR_GID
]);
708 status
= ERROR_INVALID_PARAMETER
;
709 goto out_free_values
;
711 user
->last_updated
= time(NULL
);
713 if (context
->config
.cache_ttl
) {
714 /* insert the entry into the cache */
715 cache_insert(&context
->users
, lookup
, &user
->entry
);
718 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
719 ldap_value_free(values
[i
]);
724 static int idmap_lookup_group(
725 struct idmap_context
*context
,
726 const struct idmap_lookup
*lookup
,
727 struct idmap_group
*group
)
729 PCHAR
* values
[NUM_ATTRIBUTES
] = { NULL
};
730 const unsigned attributes
= ATTR_FLAG(ATTR_GROUP_NAME
)
731 | ATTR_FLAG(ATTR_GID
);
734 /* check the group cache for an existing entry */
735 status
= cache_lookup(&context
->groups
, lookup
, &group
->entry
);
736 if (status
== NO_ERROR
) {
737 /* don't return expired entries; query new attributes
738 * and overwrite the entry with cache_insert() */
739 if (time(NULL
) - group
->last_updated
< context
->config
.cache_ttl
)
743 /* send the query to the ldap server */
744 status
= idmap_query_attrs(context
, lookup
,
745 attributes
, 0, values
, NUM_ATTRIBUTES
);
747 goto out_free_values
;
749 /* parse attributes */
750 if (FAILED(StringCchCopyA(group
->name
, VAL_LEN
,
751 *values
[ATTR_GROUP_NAME
]))) {
752 eprintf("ldap attribute %s='%s' longer than %u characters\n",
753 context
->config
.attributes
[ATTR_GROUP_NAME
],
754 *values
[ATTR_GROUP_NAME
], VAL_LEN
);
755 status
= ERROR_BUFFER_OVERFLOW
;
756 goto out_free_values
;
758 if (!parse_uint(*values
[ATTR_GID
], &group
->gid
)) {
759 eprintf("failed to parse ldap attribute %s='%s'\n",
760 context
->config
.attributes
[ATTR_GID
], *values
[ATTR_GID
]);
761 status
= ERROR_INVALID_PARAMETER
;
762 goto out_free_values
;
764 group
->last_updated
= time(NULL
);
766 if (context
->config
.cache_ttl
) {
767 /* insert the entry into the cache */
768 cache_insert(&context
->groups
, lookup
, &group
->entry
);
771 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
772 ldap_value_free(values
[i
]);
778 /* public idmap interface */
779 int nfs41_idmap_create(
780 struct idmap_context
**context_out
)
782 struct idmap_context
*context
;
783 int status
= NO_ERROR
;
785 context
= calloc(1, sizeof(struct idmap_context
));
786 if (context
== NULL
) {
787 status
= GetLastError();
791 /* initialize the caches */
792 cache_init(&context
->users
, &user_cache_ops
);
793 cache_init(&context
->groups
, &group_cache_ops
);
795 /* load ldap configuration from file */
796 status
= config_init(&context
->config
);
798 eprintf("config_init() failed with %d\n", status
);
802 /* initialize ldap and configure options */
803 context
->ldap
= ldap_init(context
->config
.hostname
, context
->config
.port
);
804 if (context
->ldap
== NULL
) {
805 status
= LdapGetLastError();
806 eprintf("ldap_init(%s) failed with %d: %s\n",
807 context
->config
.hostname
, status
, ldap_err2stringA(status
));
808 status
= LdapMapErrorToWin32(status
);
812 status
= ldap_set_option(context
->ldap
, LDAP_OPT_PROTOCOL_VERSION
,
813 (void *)&context
->config
.version
);
814 if (status
!= LDAP_SUCCESS
) {
815 eprintf("ldap_set_option(version=%d) failed with %d\n",
816 context
->config
.version
, status
);
817 status
= LdapMapErrorToWin32(status
);
821 if (context
->config
.timeout
) {
822 status
= ldap_set_option(context
->ldap
, LDAP_OPT_TIMELIMIT
,
823 (void *)&context
->config
.timeout
);
824 if (status
!= LDAP_SUCCESS
) {
825 eprintf("ldap_set_option(timeout=%d) failed with %d\n",
826 context
->config
.timeout
, status
);
827 status
= LdapMapErrorToWin32(status
);
832 *context_out
= context
;
837 nfs41_idmap_free(context
);
841 void nfs41_idmap_free(
842 struct idmap_context
*context
)
844 /* clean up the connection */
846 ldap_unbind(context
->ldap
);
848 cache_cleanup(&context
->users
);
849 cache_cleanup(&context
->groups
);
854 /* username -> uid, gid */
855 static int username_cmp(const struct list_entry
*list
, const void *value
)
857 const struct idmap_user
*entry
= list_container(list
,
858 const struct idmap_user
, entry
);
859 const char *username
= (const char*)value
;
860 return strcmp(entry
->username
, username
);
863 int nfs41_idmap_name_to_ids(
864 struct idmap_context
*context
,
865 const char *username
,
869 struct idmap_lookup lookup
= { ATTR_USER_NAME
,
870 CLASS_USER
, TYPE_STR
, username_cmp
};
871 struct idmap_user user
;
875 return ERROR_FILE_NOT_FOUND
;
877 dprintf(IDLVL
, "--> nfs41_idmap_name_to_ids('%s')\n", username
);
879 lookup
.value
= username
;
881 /* look up the user entry */
882 status
= idmap_lookup_user(context
, &lookup
, &user
);
884 dprintf(IDLVL
, "<-- nfs41_idmap_name_to_ids('%s') "
885 "failed with %d\n", username
, status
);
891 dprintf(IDLVL
, "<-- nfs41_idmap_name_to_ids('%s') "
892 "returning uid=%u, gid=%u\n", username
, user
.uid
, user
.gid
);
897 /* uid -> username */
898 static int uid_cmp(const struct list_entry
*list
, const void *value
)
900 const struct idmap_user
*entry
= list_container(list
,
901 const struct idmap_user
, entry
);
902 const UINT_PTR uid
= (const UINT_PTR
)value
;
903 return (UINT
)uid
- entry
->uid
;
906 int nfs41_idmap_uid_to_name(
907 struct idmap_context
*context
,
912 UINT_PTR uidp
= uid
; /* convert to pointer size to pass as void* */
913 struct idmap_lookup lookup
= { ATTR_UID
, CLASS_USER
, TYPE_INT
, uid_cmp
};
914 struct idmap_user user
;
917 dprintf(IDLVL
, "--> nfs41_idmap_uid_to_name(%u)\n", uid
);
919 lookup
.value
= (const void*)uidp
;
921 /* look up the user entry */
922 status
= idmap_lookup_user(context
, &lookup
, &user
);
924 dprintf(IDLVL
, "<-- nfs41_idmap_uid_to_name(%u) "
925 "failed with %d\n", uid
, status
);
929 if (FAILED(StringCchCopyA(name
, len
, user
.username
))) {
930 status
= ERROR_BUFFER_OVERFLOW
;
931 eprintf("username buffer overflow: '%s' > %u\n",
936 dprintf(IDLVL
, "<-- nfs41_idmap_uid_to_name(%u) "
937 "returning '%s'\n", uid
, name
);
942 /* principal -> uid, gid */
943 static int principal_cmp(const struct list_entry
*list
, const void *value
)
945 const struct idmap_user
*entry
= list_container(list
,
946 const struct idmap_user
, entry
);
947 const char *principal
= (const char*)value
;
948 return strcmp(entry
->principal
, principal
);
951 int nfs41_idmap_principal_to_ids(
952 struct idmap_context
*context
,
953 const char *principal
,
957 struct idmap_lookup lookup
= { ATTR_PRINCIPAL
,
958 CLASS_USER
, TYPE_STR
, principal_cmp
};
959 struct idmap_user user
;
962 dprintf(IDLVL
, "--> nfs41_idmap_principal_to_ids('%s')\n", principal
);
964 lookup
.value
= principal
;
966 /* look up the user entry */
967 status
= idmap_lookup_user(context
, &lookup
, &user
);
969 dprintf(IDLVL
, "<-- nfs41_idmap_principal_to_ids('%s') "
970 "failed with %d\n", principal
, status
);
976 dprintf(IDLVL
, "<-- nfs41_idmap_principal_to_ids('%s') "
977 "returning uid=%u, gid=%u\n", principal
, user
.uid
, user
.gid
);
983 static int group_cmp(const struct list_entry
*list
, const void *value
)
985 const struct idmap_group
*entry
= list_container(list
,
986 const struct idmap_group
, entry
);
987 const char *group
= (const char*)value
;
988 return strcmp(entry
->name
, group
);
991 int nfs41_idmap_group_to_gid(
992 struct idmap_context
*context
,
996 struct idmap_lookup lookup
= { ATTR_GROUP_NAME
,
997 CLASS_GROUP
, TYPE_STR
, group_cmp
};
998 struct idmap_group group
;
1001 dprintf(IDLVL
, "--> nfs41_idmap_group_to_gid('%s')\n", name
);
1003 lookup
.value
= name
;
1005 /* look up the group entry */
1006 status
= idmap_lookup_group(context
, &lookup
, &group
);
1008 dprintf(IDLVL
, "<-- nfs41_idmap_group_to_gid('%s') "
1009 "failed with %d\n", name
, status
);
1013 *gid_out
= group
.gid
;
1014 dprintf(IDLVL
, "<-- nfs41_idmap_group_to_gid('%s') "
1015 "returning %u\n", name
, group
.gid
);
1021 static int gid_cmp(const struct list_entry
*list
, const void *value
)
1023 const struct idmap_group
*entry
= list_container(list
,
1024 const struct idmap_group
, entry
);
1025 const UINT_PTR gid
= (const UINT_PTR
)value
;
1026 return (UINT
)gid
- entry
->gid
;
1029 int nfs41_idmap_gid_to_group(
1030 struct idmap_context
*context
,
1035 UINT_PTR gidp
= gid
; /* convert to pointer size to pass as void* */
1036 struct idmap_lookup lookup
= { ATTR_GID
, CLASS_GROUP
, TYPE_INT
, gid_cmp
};
1037 struct idmap_group group
;
1040 dprintf(IDLVL
, "--> nfs41_idmap_gid_to_group(%u)\n", gid
);
1042 lookup
.value
= (const void*)gidp
;
1044 /* look up the group entry */
1045 status
= idmap_lookup_group(context
, &lookup
, &group
);
1047 dprintf(IDLVL
, "<-- nfs41_idmap_gid_to_group(%u) "
1048 "failed with %d\n", gid
, status
);
1052 if (FAILED(StringCchCopyA(name
, len
, group
.name
))) {
1053 status
= ERROR_BUFFER_OVERFLOW
;
1054 eprintf("group name buffer overflow: '%s' > %u\n",
1059 dprintf(IDLVL
, "<-- nfs41_idmap_gid_to_group(%u) "
1060 "returning '%s'\n", gid
, name
);