diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index eb6e6589a..3eeb6ceae 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,10 @@ +2014-05-15 Corinna Vinschen + + * external.cc (cygwin_internal): Implement CW_CYGNAME_FROM_WINNAME. + Add lengthy comment to explain what we do and why. + * include/sys/cygwin.h (cygwin_getinfo_types): Add + CW_CYGNAME_FROM_WINNAME. + 2014-05-14 Corinna Vinschen * sec_auth.cc (get_server_groups): Call get_logon_server only for diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc index 8eec5b1db..4480375be 100644 --- a/winsup/cygwin/external.cc +++ b/winsup/cygwin/external.cc @@ -619,6 +619,61 @@ cygwin_internal (cygwin_getinfo_types t, ...) } break; + case CW_CYGNAME_FROM_WINNAME: + { + /* This functionality has been added mainly for sshd. Sshd + calls getpwnam() with the username of the non-privileged + user used for privilege separation. This is usually a + fixed string "sshd". However, when using usernames from + the Windows DBs, it's no safe bet anymore if the username + is "sshd", it could also be "DOMAIN+sshd". So what we do + here is this: + + Sshd calls cygwin_internal (CW_CYGNAME_FROM_WINNAME, + "sshd", + username_buffer, + sizeof username_buffer); + + If this call succeeds, sshd expects the correct Cygwin + username of the unprivileged sshd account in username_buffer. + + The below code checks for a Windows username matching the + incoming username, and then fetches the Cygwin username with + the matching SID. This is our username used for privsep then. + + Of course, other applications with similar needs can use the + same method. */ + const char *winname = va_arg (arg, const char *); + char *buffer = va_arg (arg, char *); + size_t buflen = va_arg (arg, size_t); + + if (!winname || !buffer || !buflen) + break; + + PWCHAR name; + if (!sys_mbstowcs_alloc (&name, HEAP_BUF, winname)) + break; + + cygsid sid; + DWORD slen = SECURITY_MAX_SID_SIZE; + WCHAR dom[DNLEN + 1]; + DWORD dlen = DNLEN + 1; + SID_NAME_USE acc_type; + + if (!LookupAccountNameW (NULL, name, sid, &slen, dom, &dlen, + &acc_type)) + break; + + struct passwd *pw = internal_getpwsid (sid); + if (!pw) + break; + + buffer[0] = '\0'; + strncat (buffer, pw->pw_name, buflen - 1); + res = 0; + } + break; + default: set_errno (ENOSYS); } diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 17fa12d43..7e344ecab 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -149,7 +149,8 @@ typedef enum CW_ENDENT, CW_GETNSSSEP, CW_GETPWSID, - CW_GETGRSID + CW_GETGRSID, + CW_CYGNAME_FROM_WINNAME } cygwin_getinfo_types; #define CW_LOCK_PINFO CW_LOCK_PINFO @@ -206,6 +207,7 @@ typedef enum #define CW_GETNSSSEP CW_GETNSSSEP #define CW_GETPWSID CW_GETPWSID #define CW_GETGRSID CW_GETGRSID +#define CW_CYGNAME_FROM_WINNAME CW_CYGNAME_FROM_WINNAME /* Token type for CW_SET_EXTERNAL_TOKEN */ enum