[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: 2nd call: binary incompatibility (another monkey wrench?)



Fred Romelfanger wrote:
> Another point of confusion I have found with the docs (from the Solaris side)
> is what **'s really mean in the conversation function.  When I started with
> pam under 2.6 I assumed they were an array of pointers.  What I have found in
> practice is that they are pointers to an array.  I haven't looked at the
> source for the Linux implementation (probably should), but the krb5/pam
> implementation seems to assume they are an array of pointers as I had
> originally assumed.  The following snipit seems to work under Solaris 2.6:

This is the prototype from Linux-PAM:

struct pam_conv {
    int (*conv)(int num_msg, const struct pam_message **msg,
                struct pam_response **resp, void *appdata_ptr);
    void *appdata_ptr;
};

(note the 'const' which you know is 'right'(TM) and is likely to be in Sun's
next release -- based on my conversations with Vipin at Sun.)

Don't worry.  Unless their C compiler is severely broken, we are compatible
with what the **'s mean at least.

Explanation:

In the case of your msg (below my pmsg) we are dealing with a pointer to a
'struct pam_message' pointer (an array of pointers), and in the case of resp
this is the address of a pam_response pointer (which is thus a pointer to an
array of pam_response _structures_) -- yes it is confusing and yes they
_are_different_(!)
 
Example (from pam_pwdb):

        struct pam_message msg[3],*pmsg[3];
        struct pam_response *resp;
        int i,expect;

        /* prepare to converse */

        if ( comment != NULL && off(UNIX__QUIET, ctrl) ) {
            pmsg[0] = &msg[0];
            msg[0].msg_style = PAM_TEXT_INFO;
            msg[0].msg = comment;
            i = 1;
        } else {
            i = 0;
        }

        pmsg[i] = &msg[i];
        msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
        msg[i++].msg = prompt1;

        if ( prompt2 != NULL ) {
            pmsg[i] = &msg[i];
            msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
            msg[i++].msg = prompt2;
            expect = 2;
        } else
            expect = 1;

        resp = NULL;

        retval = converse(pamh, ctrl, i, pmsg, &resp);

        if (resp != NULL) {

            /* interpret the response */

            if (retval == PAM_SUCCESS) {     /* a good conversation */

                token = xstrdup(resp[0].resp);
                if (token != NULL) {
                    if (expect == 2) {

                        /* verify that password entered correctly */
                        if (!resp[1].resp
                            || strcmp(token,resp[1].resp)) {
                            token = _pam_delete(token); /* mistyped */
                            retval = PAM_AUTHTOK_RECOVER_ERR;
 
	....

> I only ran into problem when I tried to pass more than one message or get
> more than one response.  Responses seem to work the same way as messages.

Note the 'expect' variable indicates how large an array we expect for the
responses (this is always the number of msg's for Sun but for us it is the
number of prompts = #msg's -1 in this case).  But more importantly, note
that the resp[1] is a _structure_ and not a pointer to a structure..

Read all this again and it may make sense.  I suggest some paper and a
pencil.  (I tore out my hair over this when I wrote this code 18 months ago. 
Yes, it was so bad I still remember ;^)

Cheers

Andrew "Get that level of support from anyone you paid lately?" ;^)
-- 
               Linux-PAM, libpwdb, Orange-Linux and Linux-GSS
                  http://parc.power.net/morgan/index.html



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] []