Server library functions must know how many and what type of arguments to expect, and must operate on those arguments correctly, based on the API version with which they are invoked. The API version is contained in the handle that is alwasy passed as their first argument, generated by kadm5_init_* (to which the client specified the API version to use at run-time).
In general, it is probably unsafe for a compiled function in a library
to re-interpret the number and type of defined arguments at run-time
since the calling conventions may not allow it; for example, a
function whose first argument was a short in one version and a pointer
in the next might fail if it simply typed-casted the argument. In
that case, the function would have to written to take variable
arguments (i.e. use stdarg.h
) and extract them from the stack
based on the API version. Alternatively, a separate function for each
API version could be defined, and
kadm5/admin.h
could be written
to
#1
the exported function name based on the value of
USE_KADM5_API_VERSION.
In the current system, it turns out, that isn't necessary, and future implementors should take try to ensure that no version has semantics that will cause such problems in the future. All the functions in KADM5 that have different arguments or results between VERSION_1 and VERSION_2 do so simply by type-casting their arguments to the appropriate version and then have separate code paths to handle each one correctly. kadm5_get_principal, in svr_principal.c, is a good example. In VERSION_1, it took the address of a pointer to a kadm5_principal_ent_t to fill in with a pointer to allocated memory; in VERSION_2, it takes a pointer to a structure to fill in, and a mask of which fields in that structure should be filled in. Also, the contents of the kadm5_principal_ent_t changed slightly between the two versions. kadm5_get_principal handles versioning as follows (following along in the source code will be helpful):
There is another complication involved in a function re-interpreting the number of arguments it receives at compile time--it cannot assign any value to an argument for which the client did not pass a value. For example, a VERSION_1 client only passes three arguments to kadm5_get_principal. If the implementation of kadm5_get_principal notices that the caller is VERSION_1 and therefore assigns its fourth argument, mask, to a value that mimics the VERSION_1 behavior, it may inadvertently overwrite data on its caller's stack. This problem can be avoided simply by using a true local variable in such cases, instead of treating an unpassed argument as a local variable.