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
;
79 static const char CONFIG_FILENAME
[] = "C:\\ReactOS\\System32\\drivers\\etc\\ms-nfs41-idmap.conf";
83 /* ldap server information */
84 char hostname
[NFS41_HOSTNAME_LEN
+1];
89 /* ldap schema information */
90 char classes
[NUM_CLASSES
][NAME_LEN
];
91 char attributes
[NUM_ATTRIBUTES
][NAME_LEN
];
94 /* caching configuration */
104 struct config_option
{
107 enum config_type type
;
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 }
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
),
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
),
140 /* caching configuration */
141 OPT_INT("cache_ttl", "60", cache_ttl
),
145 /* parse each line into key-value pairs
146 * accepts 'key = value' or 'key = "value"',
147 * ignores whitespace anywhere outside the ""s */
149 const char *key
, *value
;
150 size_t key_len
, value_len
;
153 static int config_parse_pair(
155 struct config_pair
*pair
)
158 int status
= NO_ERROR
;
160 /* terminate at comment */
161 pos
= strchr(line
, '#');
164 /* skip whitespace before key */
166 while (isspace(*pos
)) pos
++;
169 pos
= strchr(pos
, '=');
171 eprintf("missing '='\n");
172 status
= ERROR_INVALID_PARAMETER
;
176 /* skip whitespace after key */
177 pair
->key_len
= pos
- pair
->key
;
178 while (pair
->key_len
&& isspace(pair
->key
[pair
->key_len
-1]))
181 if (pair
->key_len
<= 0) {
182 eprintf("empty key\n");
183 status
= ERROR_INVALID_PARAMETER
;
187 /* skip whitespace after = */
189 while (isspace(*pos
)) pos
++;
192 eprintf("end of line looking for value\n");
193 status
= ERROR_INVALID_PARAMETER
;
198 /* value is between the "s */
199 pair
->value
= pos
+ 1;
200 pos
= strchr(pair
->value
, '\"');
202 eprintf("no matching '\"'\n");
203 status
= ERROR_INVALID_PARAMETER
;
206 pair
->value_len
= pos
- pair
->value
;
209 pair
->value_len
= strlen(pair
->value
);
211 /* skip whitespace after value */
212 while (pair
->value_len
&& isspace(pair
->value
[pair
->value_len
-1]))
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;
223 static BOOL
parse_uint(
228 const UINT id
= strtoul(str
, &endp
, 10);
230 /* must convert the whole string */
231 if ((endp
- str
) < (ptrdiff_t)strlen(str
))
234 /* result must fit in 32 bits */
235 if (id
== ULONG_MAX
&& errno
== ERANGE
)
242 /* parse default values from g_options[] into idmap_config */
243 static int config_defaults(
244 struct idmap_config
*config
)
246 const struct config_option
*option
;
247 const int count
= ARRAYSIZE(g_options
);
249 int i
, status
= NO_ERROR
;
251 for (i
= 0; i
< count
; i
++) {
252 option
= &g_options
[i
];
253 dst
= (char*)config
+ option
->offset
;
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
);
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
,
275 static int config_find_option(
276 const struct config_pair
*pair
,
277 const struct config_option
**option
)
279 int i
, count
= ARRAYSIZE(g_options
);
280 int status
= ERROR_NOT_FOUND
;
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
];
293 static int config_load(
294 struct idmap_config
*config
,
295 const char *filename
)
297 char buffer
[1024], *pos
;
299 struct config_pair pair
;
300 const struct config_option
*option
;
302 int status
= NO_ERROR
;
305 file
= fopen(filename
, "r");
307 eprintf("config_load() failed to open file '%s'\n", filename
);
312 while (fgets(buffer
, sizeof(buffer
), file
)) {
315 /* skip whitespace */
317 while (isspace(*pos
)) pos
++;
319 /* skip comments and empty lines */
320 if (*pos
== '#' || *pos
== 0)
323 /* parse line into a key=value pair */
324 status
= config_parse_pair(buffer
, &pair
);
326 eprintf("error on line %d: %s\n", line
, buffer
);
330 /* find the config_option by key */
331 status
= config_find_option(&pair
, &option
);
333 eprintf("unrecognized option '%s' on line %d: %s\n",
334 pair
.key
, line
, buffer
);
335 status
= ERROR_INVALID_PARAMETER
;
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
);
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
);
362 static int config_init(
363 struct idmap_config
*config
)
367 char config_path
[MAX_PATH
];
370 /* load default values */
371 status
= config_defaults(config
);
373 eprintf("config_defaults() failed with %d\n", status
);
378 if (GetSystemDirectoryA(config_path
, ARRAYSIZE(config_path
)))
380 StringCchCatA(config_path
, ARRAYSIZE(config_path
), "\\drivers\\etc\\ms-nfs41-idmap.conf");
384 StringCchCopyA(config_path
, ARRAYSIZE(config_path
), "C:\\ReactOS\\system32\\drivers\\etc\\ms-nfs41-idmap.conf");
388 /* load configuration from file */
390 status
= config_load(config
, config_path
);
392 status
= config_load(config
, CONFIG_FILENAME
);
396 eprintf("config_load('%s') failed with %d\n", config_path
, status
);
398 eprintf("config_load('%s') failed with %d\n", CONFIG_FILENAME
, status
);
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
*);
413 entry_alloc_fn entry_alloc
;
414 entry_free_fn entry_free
;
415 entry_copy_fn entry_copy
;
419 struct list_entry head
;
420 const struct cache_ops
*ops
;
425 static void cache_init(
426 struct idmap_cache
*cache
,
427 const struct cache_ops
*ops
)
429 list_init(&cache
->head
);
431 InitializeSRWLock(&cache
->lock
);
434 static void cache_cleanup(
435 struct idmap_cache
*cache
)
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
);
443 static int cache_insert(
444 struct idmap_cache
*cache
,
445 const struct idmap_lookup
*lookup
,
446 const struct list_entry
*src
)
448 struct list_entry
*entry
;
449 int status
= NO_ERROR
;
451 AcquireSRWLockExclusive(&cache
->lock
);
453 /* search for an existing match */
454 entry
= list_search(&cache
->head
, lookup
->value
, lookup
->compare
);
456 /* overwrite the existing entry with the new results */
457 cache
->ops
->entry_copy(entry
, src
);
461 /* initialize a new entry and add it to the list */
462 entry
= cache
->ops
->entry_alloc();
464 status
= GetLastError();
467 cache
->ops
->entry_copy(entry
, src
);
468 list_add_head(&cache
->head
, entry
);
470 ReleaseSRWLockExclusive(&cache
->lock
);
474 static int cache_lookup(
475 struct idmap_cache
*cache
,
476 const struct idmap_lookup
*lookup
,
477 struct list_entry
*entry_out
)
479 struct list_entry
*entry
;
480 int status
= ERROR_NOT_FOUND
;
482 AcquireSRWLockShared(&cache
->lock
);
484 entry
= list_search(&cache
->head
, lookup
->value
, lookup
->compare
);
486 /* make a copy for use outside of the lock */
487 cache
->ops
->entry_copy(entry_out
, entry
);
491 ReleaseSRWLockShared(&cache
->lock
);
498 struct list_entry entry
;
499 char username
[VAL_LEN
];
500 char principal
[VAL_LEN
];
506 static struct list_entry
* user_cache_alloc()
508 struct idmap_user
*user
= calloc(1, sizeof(struct idmap_user
));
509 return user
== NULL
? NULL
: &user
->entry
;
511 static void user_cache_free(struct list_entry
*entry
)
513 free(list_container(entry
, struct idmap_user
, entry
));
515 static void user_cache_copy(
516 struct list_entry
*lhs
,
517 const struct list_entry
*rhs
)
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
);
521 StringCchCopyA(dst
->username
, VAL_LEN
, src
->username
);
522 StringCchCopyA(dst
->principal
, VAL_LEN
, src
->principal
);
525 dst
->last_updated
= src
->last_updated
;
527 static const struct cache_ops user_cache_ops
= {
536 struct list_entry entry
;
542 static struct list_entry
* group_cache_alloc()
544 struct idmap_group
*group
= calloc(1, sizeof(struct idmap_group
));
545 return group
== NULL
? NULL
: &group
->entry
;
547 static void group_cache_free(struct list_entry
*entry
)
549 free(list_container(entry
, struct idmap_group
, entry
));
551 static void group_cache_copy(
552 struct list_entry
*lhs
,
553 const struct list_entry
*rhs
)
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
);
559 dst
->last_updated
= src
->last_updated
;
561 static const struct cache_ops group_cache_ops
= {
569 struct idmap_context
{
570 struct idmap_config config
;
571 struct idmap_cache users
;
572 struct idmap_cache groups
;
577 static int idmap_filter(
578 struct idmap_config
*config
,
579 const struct idmap_lookup
*lookup
,
584 int status
= NO_ERROR
;
586 switch (lookup
->type
) {
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
);
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
);
611 status
= ERROR_INVALID_PARAMETER
;
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
,
625 char filter
[FILTER_LEN
];
626 struct idmap_config
*config
= &context
->config
;
627 LDAPMessage
*res
= NULL
, *entry
;
630 /* format the ldap filter */
631 status
= idmap_filter(config
, lookup
, filter
, FILTER_LEN
);
635 /* send the ldap query */
636 status
= ldap_search_st(context
->ldap
, config
->base
,
637 LDAP_SCOPE_SUBTREE
, filter
, NULL
, 0, NULL
, &res
);
639 eprintf("ldap search for '%s' failed with %d: %s\n",
640 filter
, status
, ldap_err2stringA(status
));
641 status
= LdapMapErrorToWin32(status
);
645 entry
= ldap_first_entry(context
->ldap
, res
);
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
);
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
]);
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
);
673 if (res
) ldap_msgfree(res
);
677 static int idmap_lookup_user(
678 struct idmap_context
*context
,
679 const struct idmap_lookup
*lookup
,
680 struct idmap_user
*user
)
682 PCHAR
* values
[NUM_ATTRIBUTES
] = { NULL
};
683 const unsigned attributes
= ATTR_FLAG(ATTR_USER_NAME
)
684 | ATTR_FLAG(ATTR_PRINCIPAL
)
685 | ATTR_FLAG(ATTR_UID
)
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
);
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
)
700 /* send the query to the ldap server */
701 status
= idmap_query_attrs(context
, lookup
,
702 attributes
, optional
, values
, NUM_ATTRIBUTES
);
704 goto out_free_values
;
706 /* parse attributes */
707 if (FAILED(StringCchCopyA(user
->username
, VAL_LEN
,
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
;
715 if (FAILED(StringCchCopyA(user
->principal
, VAL_LEN
,
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
;
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
;
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
;
735 user
->last_updated
= time(NULL
);
737 if (context
->config
.cache_ttl
) {
738 /* insert the entry into the cache */
739 cache_insert(&context
->users
, lookup
, &user
->entry
);
742 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
743 ldap_value_free(values
[i
]);
748 static int idmap_lookup_group(
749 struct idmap_context
*context
,
750 const struct idmap_lookup
*lookup
,
751 struct idmap_group
*group
)
753 PCHAR
* values
[NUM_ATTRIBUTES
] = { NULL
};
754 const unsigned attributes
= ATTR_FLAG(ATTR_GROUP_NAME
)
755 | ATTR_FLAG(ATTR_GID
);
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
)
767 /* send the query to the ldap server */
768 status
= idmap_query_attrs(context
, lookup
,
769 attributes
, 0, values
, NUM_ATTRIBUTES
);
771 goto out_free_values
;
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
;
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
;
788 group
->last_updated
= time(NULL
);
790 if (context
->config
.cache_ttl
) {
791 /* insert the entry into the cache */
792 cache_insert(&context
->groups
, lookup
, &group
->entry
);
795 for (i
= 0; i
< NUM_ATTRIBUTES
; i
++)
796 ldap_value_free(values
[i
]);
802 /* public idmap interface */
803 int nfs41_idmap_create(
804 struct idmap_context
**context_out
)
806 struct idmap_context
*context
;
807 int status
= NO_ERROR
;
809 context
= calloc(1, sizeof(struct idmap_context
));
810 if (context
== NULL
) {
811 status
= GetLastError();
815 /* initialize the caches */
816 cache_init(&context
->users
, &user_cache_ops
);
817 cache_init(&context
->groups
, &group_cache_ops
);
819 /* load ldap configuration from file */
820 status
= config_init(&context
->config
);
822 eprintf("config_init() failed with %d\n", status
);
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
);
836 status
= ldap_set_option(context
->ldap
, LDAP_OPT_PROTOCOL_VERSION
,
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
);
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
);
856 *context_out
= context
;
861 nfs41_idmap_free(context
);
865 void nfs41_idmap_free(
866 struct idmap_context
*context
)
868 /* clean up the connection */
870 ldap_unbind(context
->ldap
);
872 cache_cleanup(&context
->users
);
873 cache_cleanup(&context
->groups
);
878 /* username -> uid, gid */
879 static int username_cmp(const struct list_entry
*list
, const void *value
)
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
);
887 int nfs41_idmap_name_to_ids(
888 struct idmap_context
*context
,
889 const char *username
,
893 struct idmap_lookup lookup
= { ATTR_USER_NAME
,
894 CLASS_USER
, TYPE_STR
, username_cmp
};
895 struct idmap_user user
;
899 return ERROR_FILE_NOT_FOUND
;
901 dprintf(IDLVL
, "--> nfs41_idmap_name_to_ids('%s')\n", username
);
903 lookup
.value
= username
;
905 /* look up the user entry */
906 status
= idmap_lookup_user(context
, &lookup
, &user
);
908 dprintf(IDLVL
, "<-- nfs41_idmap_name_to_ids('%s') "
909 "failed with %d\n", username
, status
);
915 dprintf(IDLVL
, "<-- nfs41_idmap_name_to_ids('%s') "
916 "returning uid=%u, gid=%u\n", username
, user
.uid
, user
.gid
);
921 /* uid -> username */
922 static int uid_cmp(const struct list_entry
*list
, const void *value
)
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
;
930 int nfs41_idmap_uid_to_name(
931 struct idmap_context
*context
,
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
;
941 dprintf(IDLVL
, "--> nfs41_idmap_uid_to_name(%u)\n", uid
);
943 lookup
.value
= (const void*)uidp
;
945 /* look up the user entry */
946 status
= idmap_lookup_user(context
, &lookup
, &user
);
948 dprintf(IDLVL
, "<-- nfs41_idmap_uid_to_name(%u) "
949 "failed with %d\n", uid
, status
);
953 if (FAILED(StringCchCopyA(name
, len
, user
.username
))) {
954 status
= ERROR_BUFFER_OVERFLOW
;
955 eprintf("username buffer overflow: '%s' > %u\n",
960 dprintf(IDLVL
, "<-- nfs41_idmap_uid_to_name(%u) "
961 "returning '%s'\n", uid
, name
);
966 /* principal -> uid, gid */
967 static int principal_cmp(const struct list_entry
*list
, const void *value
)
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
);
975 int nfs41_idmap_principal_to_ids(
976 struct idmap_context
*context
,
977 const char *principal
,
981 struct idmap_lookup lookup
= { ATTR_PRINCIPAL
,
982 CLASS_USER
, TYPE_STR
, principal_cmp
};
983 struct idmap_user user
;
986 dprintf(IDLVL
, "--> nfs41_idmap_principal_to_ids('%s')\n", principal
);
988 lookup
.value
= principal
;
990 /* look up the user entry */
991 status
= idmap_lookup_user(context
, &lookup
, &user
);
993 dprintf(IDLVL
, "<-- nfs41_idmap_principal_to_ids('%s') "
994 "failed with %d\n", principal
, status
);
1000 dprintf(IDLVL
, "<-- nfs41_idmap_principal_to_ids('%s') "
1001 "returning uid=%u, gid=%u\n", principal
, user
.uid
, user
.gid
);
1007 static int group_cmp(const struct list_entry
*list
, const void *value
)
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
);
1015 int nfs41_idmap_group_to_gid(
1016 struct idmap_context
*context
,
1020 struct idmap_lookup lookup
= { ATTR_GROUP_NAME
,
1021 CLASS_GROUP
, TYPE_STR
, group_cmp
};
1022 struct idmap_group group
;
1025 dprintf(IDLVL
, "--> nfs41_idmap_group_to_gid('%s')\n", name
);
1027 lookup
.value
= name
;
1029 /* look up the group entry */
1030 status
= idmap_lookup_group(context
, &lookup
, &group
);
1032 dprintf(IDLVL
, "<-- nfs41_idmap_group_to_gid('%s') "
1033 "failed with %d\n", name
, status
);
1037 *gid_out
= group
.gid
;
1038 dprintf(IDLVL
, "<-- nfs41_idmap_group_to_gid('%s') "
1039 "returning %u\n", name
, group
.gid
);
1045 static int gid_cmp(const struct list_entry
*list
, const void *value
)
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
;
1053 int nfs41_idmap_gid_to_group(
1054 struct idmap_context
*context
,
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
;
1064 dprintf(IDLVL
, "--> nfs41_idmap_gid_to_group(%u)\n", gid
);
1066 lookup
.value
= (const void*)gidp
;
1068 /* look up the group entry */
1069 status
= idmap_lookup_group(context
, &lookup
, &group
);
1071 dprintf(IDLVL
, "<-- nfs41_idmap_gid_to_group(%u) "
1072 "failed with %d\n", gid
, status
);
1076 if (FAILED(StringCchCopyA(name
, len
, group
.name
))) {
1077 status
= ERROR_BUFFER_OVERFLOW
;
1078 eprintf("group name buffer overflow: '%s' > %u\n",
1083 dprintf(IDLVL
, "<-- nfs41_idmap_gid_to_group(%u) "
1084 "returning '%s'\n", gid
, name
);