RSS

Monthly Archives: January 2014

NSS Responder

There are mainly two responders in SSSD: NSS and PAM.

The role of a Responder is:

  1. it receives request messages from a matching SSS Client
  2. fulfills the requests in one of two following ways:
  3. Either directly retrieving a valid cached result from the sysdb Cache, or
  4. Or asks the Backend to update the sysdb Cache and then retrieves an up-to-date result from the sysdb Cache.
  5. sends back response messages to the matching SSS Client

The NSS server consists of two major task of: the NSS client and the Data Provider. The NSS client requests data (request for user by name or by id etc )and receives the result from the NSS responder.

A very simple way to understand the flow can be following: As explained by my mentor (Jakub Jhrozek) 🙂
“The Data Provider can be though of as “the server”. It is the component that is called when there is no data available to the NSS responder. Maybe it would be easier to grasp how the NSS responder works with a
mini-algorithm:
0. Request comes in to gather data about an entity. This is
simulated in the test by calling
will_return(__wrap_sss_packet_get_cmd), in real world the function
sss_packet_get_cmd is called.
1. The NSS responder checks if the data is available in the cache by
calling the sysdb functions.
1a. If the data is available in the cache, it is returned. The
request ends, go to 2.
1b. If the data is not available in the cache, the Data Provider
is asked for the data. Execution waits for the Data Provider to
finish and then returns to 1.
1c. If the data is not available in the cache and the Data
Provider was checked already, set negative result and go to 2.
2. Result (positive or negative) is returned to the client. “
Now, let us take a function in order to understand its working:
/* Testsuite for getuid */
static void mock_input_id(uint8_t *id)
{
will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
will_return(__wrap_sss_packet_get_body, id);
}
static int test_nss_getpwuid_check(uint32_t status, uint8_t *body, size_t blen)
{
struct passwd pwd;
errno_t ret;assert_int_equal(status, EOK);ret = parse_user_packet(body, blen, &pwd);
assert_int_equal(ret, EOK);assert_int_equal(pwd.pw_uid, 101);
assert_int_equal(pwd.pw_gid, 401);
assert_string_equal(pwd.pw_name, “testuser1”);
assert_string_equal(pwd.pw_shell, “/bin/sh”);
assert_string_equal(pwd.pw_passwd, “*”);
return EOK;
}
void test_nss_getpwuid(void **state)
{
errno_t ret;/* Prime the cache with a valid user */
ret = sysdb_add_user(nss_test_ctx->tctx->dom,
“testuser1”, 101, 401, “test user1”,
“/home/testuser1”, “/bin/sh”, NULL,
NULL, 300, 0);
assert_int_equal(ret, EOK);uint8_t id = 101;
mock_input_id(&id);
will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID);
mock_fill_user();/* Query for that user, call a callback when command finishes */
set_cmd_cb(test_nss_getpwuid_check);
ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID,
nss_test_ctx->nss_cmds);
assert_int_equal(ret, EOK);/* Wait until the test finishes with EOK */
ret = test_ev_loop(nss_test_ctx->tctx);
assert_int_equal(ret, EOK);
}
Let us look into the above function test_nss_getpwuid()
1)
/* Prime the cache with a valid user */
ret = sysdb_add_user(nss_test_ctx->tctx->dom,
“testuser1”, 101, 401, “test user1”,
“/home/testuser1”, “/bin/sh”, NULL,
NULL, 300, 0);
We are adding a valid user to system database.
2)
mock_input_id(&id);
will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETPWUID);
mock_fill_user();
Here, we are creating dummy packet with the above statements. Our test driver will be named __wrap_sss_packet_get_cmd() and this will replace the original sss_packet_get_cmd() function. We use __wrap since a linker flag makes it easy to “wrap” calls when named starting with “__wrap”.
will_return(function, value) : This way “value” is enqueued to the queue of mock values.
mock() : Likewise with mock() call, one value is dequeued from the mock value queue. We are writing mock of the original function, which instructs what value to be returned once mock is called in the function. mock_input_id() that will instruct __wrap_sss_packet_get_body() mentioned above, to return a uint32_t in the buffer.
3)
/* Query for that user, call a callback when command finishes */
set_cmd_cb(test_nss_getpwuid_check);
ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETPWUID,
nss_test_ctx->nss_cmds);
With sss_cmd_execute we tell program to ‘execute GETPWUID‘ and when that is ready, call test_nss_getpwuid_check(), written above. The function nss_cmd_getpwnuid will then get executed and it will read the data we prepared with mock_input_id(). When whole processing finishes, the callback test_nss_getpwnam_check will get executed.
Let us discuss more about other functionalities it in upcoming posts 🙂
Advertisements
 
Leave a comment

Posted by on January 28, 2014 in Uncategorized

 

Somewhat about Tevent Context!

Tevent context is a handler that describes an instance of the ‘tevent’ event library. Thus to work with this, first we need to allocate some memory say “memctx”. Now that we have space allocated, we will put our tevent_ctx pointer here. To deal with the events to be caught and handled they are first required to be included in this particular context. Reason for subordinating events to a tevent context structure rises from the fact that several context can be created and each of them are processed at different time. Thus we can maintain different context for different events. For example: we can have one context containing just file descriptor events, secondone taking care of signal and time events and the third one which keeps information about the rest etc.

// A little example:

TALLOC_CTX *memctx = talloc_new(NULL);
assert_non_null(memctx, NULL);
struct tevent_context *ev_ctx = tevent_context_init(memctx);
assert_non_null(ev_ctx, NULL);

The Diagram below explains the idea clearly: Taken from the source mentioned below.

tevent_context_stucture.png

Source : https://tevent.samba.org/tevent_tutorial.html

 
Leave a comment

Posted by on January 26, 2014 in Uncategorized

 

Negative Cache

My last module work was on negative cache. While writing unit test for the module I gathered some knowledge about negative caching. Let us have a brief look into it!

Simple Defination:

DNS caching of unsuccessful name resolution attempts is called negative caching.

Elaboration:

Let us understand it more elaborately. Resolver receives positive or negative responses to different queries. Accordingly it adds the respective response to its cache. The resolver always checks the cache before querying any DNS servers. If a name is in the cache, the resolver uses the name from the cache rather than querying a server. Since there is no resource record for an invalid name the server itself must decide how long to cache this negative information. Thus if a negative response is cached for a query it does not try to resolve it later rather sends the same response as a result of the query asked again.

Use of Negative Cache:

Negative caching is useful as it reduces the response time for negative answers. It also reduces the number of messages that have to be sent between resolvers and name servers hence overall network traffic. A large proportion of DNS traffic on the Internet could be eliminated if all resolvers implemented negative caching.

The ISPs which have multiple DNS servers take advantage of negative response and other response type cached to distinguish between different DNS servers. The failed DNS entry remains as long as the TTL is set. After TTL, DNS server is requeried because after this particular time limit the response entry will be dropped from the cache. But, the negative response still persists in the cache. That negative response prevents the machine from asking that particular DNS server, and instead it asks another server. This prevents a timeout error if that machine fails to respond. Even the negative response will be dropped later. Later DNS server which issued negative response may update itself by then.

 

 
Leave a comment

Posted by on January 10, 2014 in Uncategorized