2 * Copyright 2012, Sine Nomine Associates and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
13 #include <opr/queue.h>
15 #include <afs/pthread_glock.h>
16 #include <afs/afsutil.h>
19 #include "cellconfig.h"
22 #define MAXLINESIZE 2047
24 /* Can be set during initialization, overriding the krb.conf file. */
25 static struct opr_queue
*lrealms
= NULL
;
28 * Realm and exclusion list entries.
30 struct afsconf_realm_entry
{
31 struct opr_queue link
; /**< linked list header */
32 char *value
; /**< local realm or principal */
36 * Realm and exclusion lists.
38 struct afsconf_realms
{
39 struct opr_queue list
; /**< list of afsconf_realm_entry */
40 int time_read
; /**< time when read from file */
41 void *tree
; /**< for lookup */
42 int (*compare
) (const void *, const void *); /**< compare entries */
46 compare_realms(const void *a
, const void *b
)
48 return strcasecmp((char *)a
, (char *)b
);
52 compare_principals(const void *a
, const void *b
)
54 return strcmp((char *)a
, (char *)b
);
58 * Format the k4-style principal string.
60 * @param[out] pvname output buffer, must be freed by caller
61 * @param[in] name user name, required
62 * @param[in] inst user instance, optional
63 * @param[in] cell cell name, optional
67 * @retval EINVAL invalid arguments
68 * @retval E2BIG insufficient output buffer space
73 create_name(char **pvname
, const char *name
,
74 const char *inst
, const char *cell
)
78 if (!name
|| !*name
) {
83 code
= asprintf(pvname
, "%s.%s@%s", name
, inst
, cell
);
85 code
= asprintf(pvname
, "%s@%s", name
, cell
);
89 code
= asprintf(pvname
, "%s.%s", name
, inst
);
91 code
= asprintf(pvname
, "%s", name
);
94 return (code
< 0 ? ENOMEM
: 0);
98 * Parse whitespace delimited values
100 * @param[in] buffer input string
101 * @param[out] result output string
102 * @param[in] size size of result buffer
104 * @return pointer to the next value
109 parse_str(char *buffer
, char *result
, int size
)
116 while (*buffer
&& isspace(*buffer
))
118 while (*buffer
&& !isspace(*buffer
)) {
120 *result
++ = *buffer
++;
133 * Add a new list element.
135 * Add the name element if not already present in the list.
136 * The names are case insensitive.
138 * @param[inout] list list of name elements
139 * @param[in] name name to add
143 * @retval ENOMEM unable to allocate new entry
148 add_entry(struct opr_queue
*list
, const char *name
)
150 struct afsconf_realm_entry
*entry
;
152 entry
= malloc(sizeof(struct afsconf_realm_entry
));
156 entry
->value
= strdup(name
);
157 opr_queue_Append(list
, (struct opr_queue
*)entry
);
162 * Free all entries in a list.
164 * @param[in] list list of entries
171 free_realm_entries(struct opr_queue
*list
)
173 struct afsconf_realm_entry
*entry
;
175 while (!opr_queue_IsEmpty(list
)) {
176 entry
= opr_queue_First(list
, struct afsconf_realm_entry
, link
);
177 opr_queue_Remove(&entry
->link
);
187 * Placeholder for tdestroy.
190 free_tree_node(void *nodep
)
197 * Delete all the entries from the search tree.
199 * @param[in] list list of entries
206 destroy_tree(struct afsconf_realms
*entries
)
210 tdestroy(entries
->tree
, free_tree_node
);
212 struct opr_queue
*cursor
;
213 struct afsconf_realm_entry
*entry
;
215 for (opr_queue_Scan(&entries
->list
, cursor
)) {
216 entry
= opr_queue_Entry(cursor
, struct afsconf_realm_entry
, link
);
217 tdelete(entry
->value
, &entries
->tree
, entries
->compare
);
220 entries
->tree
= NULL
;
225 * Build a search tree from the list of entries.
227 * @param[in] list list of entries
234 build_tree(struct afsconf_realms
*entries
)
236 struct opr_queue
*cursor
;
237 struct afsconf_realm_entry
*entry
;
239 for (opr_queue_Scan(&entries
->list
, cursor
)) {
240 entry
= opr_queue_Entry(cursor
, struct afsconf_realm_entry
, link
);
241 tsearch(entry
->value
, &entries
->tree
, entries
->compare
);
246 * Read the list of local realms from a config file.
248 * @param[inout] dir config dir object
255 read_local_realms(struct afsconf_realms
*entries
, const char *path
)
258 char realm
[AFS_REALM_SZ
];
259 struct opr_queue temp
;
260 char *filename
= NULL
;
262 FILE *cnffile
= NULL
;
263 char *linebuf
= NULL
;
266 opr_queue_Init(&temp
);
267 code
= asprintf(&filename
, "%s/%s", path
, AFSDIR_KCONF_FILE
);
272 code
= stat(filename
, &tstat
);
274 code
= (errno
== ENOENT
? 0 : errno
); /* this file is optional */
277 if (tstat
.st_mtime
== entries
->time_read
) {
281 entries
->time_read
= tstat
.st_mtime
;
282 if ((cnffile
= fopen(filename
, "r")) == NULL
) {
283 code
= (errno
== ENOENT
? 0 : errno
); /* this file is optional */
286 linebuf
= malloc(sizeof(char) * (MAXLINESIZE
+ 1));
291 if (fgets(linebuf
, MAXLINESIZE
, cnffile
) == NULL
) {
295 linebuf
[MAXLINESIZE
] = '\0';
296 for (p
= linebuf
; *p
;) {
297 p
= parse_str(p
, realm
, AFS_REALM_SZ
);
299 code
= add_entry(&temp
, realm
);
305 destroy_tree(entries
);
306 opr_queue_Swap(&temp
, &entries
->list
);
310 free_realm_entries(&temp
);
324 * Read the list of local exclusions from a config file.
326 * @param[inout] dir config dir object
333 read_local_exclusions(struct afsconf_realms
*entries
, const char *path
)
336 char *linebuf
= NULL
;
337 char *filename
= NULL
;
339 FILE *cnffile
= NULL
;
340 struct opr_queue temp
;
343 opr_queue_Init(&temp
);
344 code
= asprintf(&filename
, "%s/%s", path
, AFSDIR_KRB_EXCL_FILE
);
349 code
= stat(filename
, &tstat
);
351 code
= (errno
== ENOENT
? 0 : errno
); /* this file is optional */
354 if (tstat
.st_mtime
== entries
->time_read
) {
358 if ((cnffile
= fopen(filename
, "r")) == NULL
) {
359 code
= (errno
!= ENOENT
? errno
: 0); /* this file is optional */
362 linebuf
= malloc(sizeof(char) * (MAXLINESIZE
+ 1));
368 if (fgets(linebuf
, MAXLINESIZE
, cnffile
) == NULL
) {
371 linebuf
[MAXLINESIZE
] = '\0';
372 parse_str(linebuf
, name
, sizeof(name
));
374 code
= add_entry(&temp
, name
);
380 destroy_tree(entries
);
381 opr_queue_Swap(&temp
, &entries
->list
);
384 free_realm_entries(&temp
);
399 * Free the local realms and exclusions lists.
401 * @param[in] dir afsconf dir object
408 _afsconf_FreeRealms(struct afsconf_dir
*dir
)
411 if (dir
->local_realms
) {
412 destroy_tree(dir
->local_realms
);
413 free_realm_entries(&dir
->local_realms
->list
);
414 dir
->local_realms
= NULL
;
416 if (dir
->exclusions
) {
417 destroy_tree(dir
->exclusions
);
418 free_realm_entries(&dir
->exclusions
->list
);
419 dir
->exclusions
= NULL
;
425 * Load the local realms and exclusions lists.
427 * @param[in] dir afsconf dir object
434 _afsconf_LoadRealms(struct afsconf_dir
*dir
)
437 struct afsconf_realms
*local_realms
= NULL
;
438 struct afsconf_realms
*exclusions
= NULL
;
440 /* Create and load the list of local realms. */
441 local_realms
= calloc(1, sizeof(struct afsconf_realms
));
446 opr_queue_Init(&local_realms
->list
);
447 local_realms
->compare
= compare_realms
;
450 code
= read_local_realms(local_realms
, dir
->name
);
455 struct opr_queue
*cursor
;
456 struct afsconf_realm_entry
*entry
;
457 for (opr_queue_Scan(lrealms
, cursor
)) {
458 entry
= opr_queue_Entry(cursor
, struct afsconf_realm_entry
, link
);
459 code
= add_entry(&local_realms
->list
, entry
->value
);
464 build_tree(local_realms
);
467 /* Create and load the list of excluded principals. */
468 exclusions
= calloc(1, sizeof(struct afsconf_realms
));
473 opr_queue_Init(&exclusions
->list
);
474 exclusions
->compare
= compare_principals
;
475 code
= read_local_exclusions(exclusions
, dir
->name
);
480 dir
->local_realms
= local_realms
;
481 dir
->exclusions
= exclusions
;
486 destroy_tree(local_realms
);
487 free_realm_entries(&local_realms
->list
);
490 destroy_tree(dir
->exclusions
);
491 free_realm_entries(&exclusions
->list
);
497 * Set a local realm, instead of retrieving the local realms from the
498 * configuration file krb.conf (if it exists). Maybe called multiple
499 * times during application initialization to set one or more local
504 * @retval ENOMEM unable to allocate new entry
507 afsconf_SetLocalRealm(const char *realm
)
513 lrealms
= malloc(sizeof(struct opr_queue
));
518 opr_queue_Init(lrealms
);
520 code
= add_entry(lrealms
, realm
);
527 * Determine if a principal is local to this cell.
529 * @param[in] dir afsconf dir object
530 * @param[out] plocal set to 1 if user is local, 0 if foreign
531 * @param[in] name user name
532 * @param[in] inst user instance
533 * @param[in] cell user cell name
537 * @retval ENOMEM unable to allocate memory
538 * @retval EINVAL invalid argument
541 afsconf_IsLocalRealmMatch(struct afsconf_dir
*dir
, afs_int32
* plocal
,
542 const char *name
, const char *inst
,
546 char *localcell
= NULL
;
548 struct afsconf_realms
*local_realms
= NULL
;
549 struct afsconf_realms
*exclusions
= NULL
;
554 if (!cell
|| !*cell
) {
560 code
= _afsconf_GetLocalCell(dir
, &localcell
, 1);
564 /* Does the cell match the local cell name? */
565 if (strcasecmp(localcell
, cell
) == 0) {
566 *plocal
= 1; /* cell matches the local cell name. */
570 /* Does the cell match one of the local_realms? */
571 local_realms
= dir
->local_realms
;
572 if (!tfind(cell
, &local_realms
->tree
, local_realms
->compare
)) {
573 *plocal
= 0; /* Cell name not found in local realms. */
577 /* Local realm matches, make sure the principal is not in the
578 * exclusion list, if one. */
579 exclusions
= dir
->exclusions
;
580 if (!exclusions
->tree
) {
581 *plocal
= 1; /* Matches one of the local realms; no exclusions */
585 /* Create a full principal name for the exclusion check. */
586 code
= create_name(&tvname
, name
, inst
, cell
);
588 if (tfind(tvname
, &exclusions
->tree
, exclusions
->compare
)) {
589 *plocal
= 0; /* name found in the exclusion list */
591 *plocal
= 1; /* not in the exclusion list */