[Samba] "Samba 4" - "smbd"; "can't parse the PAC: NT_STATUS_BUFFER_TOO_SMALL" error but only for a single domain user ("Server 2008 R2" domain, "Server 2008" functional level forest).

Tris Mabbs TM-Samba201302 at Firstgrade.Co.UK
Tue Feb 26 15:58:43 MST 2013


So, I have some results.

Interesting (well, I thought so anyway :-)

First, as suggested, I put some code into "source3/auth/auth_generic.c" ("somewhere near auth3_generate_session_info_pac()") as follows:

--------
*** auth_generic-ORIG.c Tue Feb 26 22:20:07 2013
--- auth_generic.c      Tue Feb 26 20:26:33 2013
***************
*** 107,112 ****
--- 107,143 ----
        /* setup the string used by %U */
        sub_set_smb_name(username);

+ /* ##########################################################################
*/
+ /*
+  *    Dump the PAC into a file named by username for debugging.
+  *    This is a quick and dirty temporary hack so we are extremely lax about
+  *    niceties such as error checking ...
+  *    We know we have a "pac_blob" though, as otherwise we'd have been dumped
+  *    out of this function already ...
+  */
+ {
+       char    pacman[MAXPATHLEN];
+       int     saved;
+
+       (void) snprintf (pacman,
+                        sizeof (pacman),
+                        "/var/tmp/PAC-%s",
+                       (username == (char *) 0 ||
+                        username[0] == '\0' ? "<unknown>" : username));
+       DEBUG(0,
+            ("Will attempt to dump PAC (length %u) into \"%s\".\n",
+            (unsigned int) pac_blob->length,
+                           pacman));
+       saved = (int) file_save ((const char *) pacman,
+                                (const void *) pac_blob->data,
+                                (size_t)       pac_blob->length);
+       DEBUG(0,
+            ("Save to \"%s\" returned %s.\n",
+             pacman,
+            (saved ? "True" : "False")));
+ }
+ /* ##########################################################################
*/
+
        /* reload services so that the new %U is taken into account */
        lp_load(get_dyn_CONFIGFILE(), false, false, true, true);
--------

This produced absolutely nothing.  Nary a PAC dump file to be seen ...

So I went to "auth/kerberos/kerberos_pac.c", to the "kerberos_decode_pac()" function which was reporting the "ndr_pull_error()" error in the first place:

--------
*** kerberos_pac-ORIG.c Tue Feb 26 22:21:04 2013
--- kerberos_pac.c      Tue Feb 26 20:38:02 2013
***************
*** 123,128 ****
--- 123,215 ----

        bool bool_ret;

+ /* ##########################################################################
*/
+ /*
+  *    Dump the encoded PAC into a file named by principal for debugging.
+  *    This is a quick and dirty temporary hack so we are extremely lax about
+  *    niceties such as error checking ...
+  *    Note that we cheat and use the Kerberos principal name (mapping any '/'s
+  *    or '\\'s to '_'s) here rather than trying to figure out an OS username ...
+  *    If we can't work out the principal name, use our PID instead.
+  */
+ {
+ #define       VarTmp          "/var/tmp/"
+       size_t  u;
+       char    c;
+       char    *s, *t;
+       char    pacman[MAXPATHLEN];
+       char    princ[1024];
+       int     saved;
+       char    *username;
+
+       if ((void *) client_principal != (void *) 0)
+       {
+               /*
+                *      Use the client principal name, as we seem to have it ...
+                */
+               u = (size_t) client_principal->name.name_string.len;
+               if (u >= (sizeof (princ) - 1))
+               {
+                       u = sizeof (princ) - 1;
+               }
+               s = client_principal->name.name_string.val;
+               if (u > 0 &&
+                   s != (char *) 0)
+               {
+                       (void) strncpy (princ,
+                                       s,
+                                       u);
+               } else
+               {
+ #define       UnknownPrinc    "<unknown>"
+                       u = sizeof (UnknownPrinc) - 1;
+                       (void) strncpy (princ,
+                                       UnknownPrinc,
+                                       u);
+ #undef        UnknownPrinc
+               }
+               princ[u] = '\0';
+       } else
+       {
+               /*
+                *      Don't even have a valid "client_principal" to raid ...
+                *      Use the PID for the suffix; at least we can trace it ba-
+                *      ck to the user session (we hope ...).
+                */
+               (void) snprintf (princ,
+                               (sizeof (princ) - 1),
+                                "%u",
+                               (unsigned int) getpid ());
+       }
+       username = princ;
+       (void) snprintf (pacman,
+                       (sizeof (pacman) - 1),
+                        "%sPAC-NDR-%s",
+                        VarTmp,
+                       (username == (char *) 0 ||
+                        username[0] == '\0' ? "<unknown>" : username));
+       for (s = &pacman[sizeof (VarTmp) - 1]; (c = s[0]) != '\0'; s++)
+       {
+               if (c == '\\' ||
+                   c == '/')
+               {
+                       s[0] = '_';
+               }
+       }
+       DEBUG(0,
+            ("Will attempt to dump encoded PAC (length %u) into \"%s\".\n",
+            (unsigned int) pac_data_blob.length,
+                           pacman));
+       saved = (int) file_save ((const char *) pacman,
+                                (const void *) pac_data_blob.data,
+                                (size_t)       pac_data_blob.length);
+       DEBUG(0,
+            ("Save to \"%s\" returned %s.\n",
+             pacman,
+            (saved ? "True" : "False")));
+ #undef        VarTmp
+ }
+ /* ########################################################################## */
+
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        if (!tmp_ctx) {
                return NT_STATUS_NO_MEMORY;
--------

That was very slightly more complicated as I wanted to use the Kerberos principal name (if known) in creating the dump file name, so it would be easy to work out which dump file was which.

In leaving that code running for a while, it was perhaps of interest to note that although several user accounts caused dump files to be created named with their Kerberos principal name, this did not happen at all for the problematic user.  I'm not sure whether or not that's significant, but I thought it at least worth mentioning - I'm not sure what the potential code paths are into this function which may, or may not, result in the principal name being known on entry ...

Anyway, what it did get me were some NDR encoded Kerberos PAC dumps, including ones for the problematic user.
So, following Andrew's instructions, I ran (for example) "ndrdump krb5pac decode_pac in /var/tmp/PAC-NDR-1819" to examine what lay therein.

I'm not going to post the actual significant data to a public forum (obviously; and yes I know that writing the PAC dumps into "/var/tmp/" with no particular control over permissions etc. isn't the best security policy in the world, but it was fine for this testing, esp. since I'm the only sysadmin on this particular box ...).  However these parts may be of general interest:

--------
% ndrdump krb5pac decode_pac in /var/tmp/PAC-NDR-1819
pull returned NT_STATUS_BUFFER_TOO_SMALL
WARNING! 136 unread bytes
...
    decode_pac: struct decode_pac
        in: struct decode_pac
            pac: struct PAC_DATA
                num_buffers              : 0x00000005 (5)
                version                  : 0x00000000 (0)
                buffers: ARRAY(5)
                    buffers: struct PAC_BUFFER
                        type                     : PAC_TYPE_LOGON_INFO (1)
                        _ndr_size                : 0x00000248 (584)
                        info                     : *
                            info                     : union PAC_INFO(case 1)
                            logon_info: struct PAC_LOGON_INFO_CTR
                                info                     : *
                                    info: struct PAC_LOGON_INFO
                                        info3: struct netr_SamInfo3
                                            base: struct netr_SamBaseInfo
<load of correctly dumped information>
===============================================================
INTERNAL ERROR: Signal 11 in pid 8122 (4.1.0pre1-GIT-3e5acc1)
Please read the Trouble-Shooting section of the Samba HOWTO
===============================================================
PANIC: internal error

Abort (core dumped)
%
--------

So, same symptoms (as one would expect) in trying to dump out the PAC, followed by a core dump.  The information actually dumped out was correct in every detail, so the information is at least mostly correctly being decoded.

Andrew, I'll send you over the "/var/tmp/PAC-NDR-1819" file to look at, if that's still OK with you - hopefully you'll be able to make sense of what's causing the apparent misinterpretation of the PAC data.

So, I think that constitutes progress!

Cheers,

Tris.



More information about the samba mailing list