NTEA extensions for uid/gid

Christian Mueller Christian_Mueller@csgsystems.com
Thu Jan 23 03:09:00 GMT 2003


Hi all,

after ntsec became the default for cygwin (and some further changes to
ruserok()), I ran into problems running servers such as rshd depending
on .rhosts and ruserok() because I don't use ntsec and ntea doesn't
store the file's uid/gid. As a result, I can't use rshd anymore
because it complains that the .rhosts file is not owned by the correct
user.

I discussed this on the Cygwin user group but my impression was that
I'm the only one having this problem at this point and possibly one of
the few using ntea. I don't want to use ntsec because I use my Cygwin
home directory for Cygwin *and* Windows programs and ntsec displays
screwed-up file permissions for files created by Windows programs.
BTW, my user is part of the admin group because I can't change things
such as network settings on my laptop without being an "administrator".

Thus, I went ahead and modified ntea.cc and security.cc to support
uid/gid in addition to the file mode. The modified version now uses
three extended attributes:

    .UNIXATTR   - file mode (same as in current versions)
    .UNIXUID    - UID (file owner)
    .UNIXGID    - GID (file group)

I added a new function to ntea.cc, NTReadEAMulti(), which reads all
requested EAs in one step, thus there's no additional overhead besides
the few extra bytes to be read by NTReadEARaw() but that shouldn't
have any noticable impact on performance.

I did not combine the existing file mode with the uid/gid values into
a structure because this would have caused trouble with earlier
versions of Cygwin -- NTReadEA() currently returns an error if the
extended attibute is bigger than the buffer provided.

Also, I didn't write a NTWriteEAMulti() variant, yet, because I wanted
to get feedback from the Cygwin group before putting more effort into
this issue. It works as it is right now but a function
NTWriteEAMulti() would certainly speed up setting attributes.

What I'm looking for right now is some feedback on this idea.
Naturally, I would like those modifications to end up in the Cygwin
core distribution but this probably needs to be discussed properly
before being considered. I added the source changes at the bottom of
this email. They are not complete, yet, but already work for me and
should be good enough for discussion.

Thanks,
--Christian

=====================================================================

-----------
security.h:
-----------

typedef struct
    {
      const char  *attrname;
      void        *attrbuf;
      size_t       maxlen;
      size_t       len;
    } ea_multi_t;


--------
ntea.cc:
--------

/*
   * NTReadEAMulti - read multiple EAs in one step. This function is
   *                 more efficient than NTReadEA when multiple
   *                 attributes are required because it reads the
   *                 EAs only once.
   *
   * Parameters:
   *      file                  - pointer to filename
   *      eam                   - array of ea_multi_t structures with
   *                              the EAs to read
   * Return value:
   *      > 0     - number of EAs found
   *      0       - no EAs found
   *
   *      The ea_multi_t array will be updated with the EAs read; the
   *      len fields will contain the length of each attribute, 0
   *      if this particular EA was not found.
   */

int __stdcall
NTReadEAMulti (const char *file, int cnt, ea_multi_t *eam)
{
      HANDLE hFileSource;
      PFILE_FULL_EA_INFORMATION ea, sea;
      int cnt_found = 0;
      int easize;
      int i;

      /* Reset returned EA length in eam */
      for (i = 0; i < cnt; i++)
          eam[i].len = 0;

      hFileSource = CreateFile (file, FILE_READ_EA,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                &sec_none_nih, // sa
                                OPEN_EXISTING,
                                FILE_FLAG_BACKUP_SEMANTICS,
                                NULL);

      if (hFileSource == INVALID_HANDLE_VALUE)
          return 0;

      /* Read in raw array of EAs */
      ea = sea = NTReadEARaw (hFileSource, &easize);

      /* Search for requested attributes */
      while (sea)
        {
          for (i = 0; i < cnt; i++)
            {
              if (strcasematch (ea->EaName, eam[i].attrname)) /* EA
found */
                {
                  eam[i].len = min(eam[i].maxlen, ea->EaValueLength);
                  memcpy (eam[i].attrbuf,
                          ea->EaName + (ea->EaNameLength + 1),
                          eam[i].len);
                  cnt_found++;
                  break;
                }
            }

          if (ea->NextEntryOffset == 0 || ((int) ea->NextEntryOffset >
easize))
              break;
          ea = (PFILE_FULL_EA_INFORMATION) ((char *) ea +
ea->NextEntryOffset);
        }

      if (sea)
        free (sea);

      CloseHandle (hFileSource);

      return cnt_found;
}

------------
security.cc:
------------

int
get_file_attribute (int use_ntsec, const char *file,
                      int *attribute, __uid32_t *uidret,
                      __gid32_t *gidret)
{

    ....

    if (allow_ntea)
      {
        __uid32_t uid;
        __gid32_t gid;
        int attr = *attribute;
        ea_multi_t eam[] =
          {
            { ".UNIXATTR", attribute, sizeof(*attribute), 0 },
            { ".UNIXUID",  &uid,      sizeof(uid),        0 },
            { ".UNIXGID",  &gid,      sizeof(gid),        0 }
          };

        res = NTReadEAMulti (file, sizeof(eam) / sizeof(*eam), eam);
        *attribute |= attr;
        if (uidret && eam[1].len > 0)
            *uidret = uid;
        if (gidret && eam[2].len > 0)
            *gidret = gid;
      }

    ....
}

int
set_file_attribute (int use_ntsec, const char *file,
                      __uid32_t uid, __gid32_t gid, int attribute)
{
    ....

    else if (allow_ntea)
      {
        __uid32_t l_uid = myself->uid;
        __gid32_t l_gid = myself->gid;
        ea_multi_t eam[] =
	{
	  { ".UNIXUID",  &l_uid,  sizeof(l_uid),  0 },
	  { ".UNIXGID",  &l_gid,  sizeof(l_gid),  0 }
	};

        NTReadEAMulti(file, sizeof(eam) / sizeof(*eam), eam);

        if (uid != ILLEGAL_UID)
	l_uid = uid;
        if (gid != ILLEGAL_GID)
	l_gid = gid;

        if (!NTWriteEA (file, ".UNIXATTR", (char *) &attribute,
                        sizeof (attribute)) ||
	  !NTWriteEA (file, ".UNIXUID", (char *) &l_uid,
                        sizeof (l_uid)) ||
	  !NTWriteEA (file, ".UNIXGID", (char *) &l_gid,
                        sizeof (l_gid)))
	{
	  __seterrno ();
	  ret = -1;
	}
      }

    ....
}



--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/



More information about the Cygwin mailing list