diff --git a/src/Cedar/Sam.c b/src/Cedar/Sam.c index 7520e40a..9d317226 100644 --- a/src/Cedar/Sam.c +++ b/src/Cedar/Sam.c @@ -98,6 +98,347 @@ #include "CedarPch.h" + +int base64_enc_len(unsigned int plainLen) { + unsigned int n = plainLen; + return (n + 2 - ((n + 2) % 3)) / 3 * 4; +} + +PID OpenChildProcess(const char* path, char* const parameter[], int fd[] ) +{ +#ifdef OS_WIN32 + // not implemented + return -1; +#else // OS_WIN32 + // UNIX + int fds[2][2]; + PID pid; + + if (path == NULL || parameter == NULL || fd == NULL) + { + return (PID)-1; + } + + if (pipe(fds[0]) != 0) + { + return (PID)-1; + } + + if (pipe(fds[1]) != 0) + { + close(fds[0][0]); + close(fds[0][1]); + + return (PID)-1; + } + + pid = fork(); + if (pid == (PID)0) { + int iError; + + close(fds[0][1]); + close(fds[1][0]); + + if (dup2(fds[0][0], fileno(stdin)) < 0 || dup2(fds[1][1], fileno(stdout)) < 0 ) + { + close(fds[0][0]); + close(fds[1][1]); + + _exit(EXIT_FAILURE); + } + + iError = execvp(path, parameter); + + // We should never come here + close(fds[0][0]); + close(fds[1][1]); + + _exit(iError); + } + else if (pid > (PID)0) + { + close(fds[0][0]); + close(fds[1][1]); + + fd[0] = fds[1][0]; + fd[1] = fds[0][1]; + + return pid; + } + else + { + close(fds[0][0]); + close(fds[1][1]); + + close(fds[0][1]); + close(fds[1][0]); + + return -1; + } +#endif // OS_WIN32 +} + +void CloseChildProcess(PID pid, int* fd ) +{ +#ifdef OS_WIN32 + // not implemented +#else // OS_WIN32 + if( fd != 0 ) + { + close(fd[0]); + close(fd[1]); + } + + if( pid > 0 ) + { + kill(pid, SIGTERM); + } +#endif // OS_WIN32 +} + +bool SmbAuthenticate(char* name, char* password, char* domainname, char* groupname, UINT timeout, UCHAR* challenge8, UCHAR* MsChapV2_ClientResponse, UCHAR* nt_pw_hash_hash) +{ + bool auth = false; + int fds[2]; + FILE* out, *in; + PID pid; + char buffer[255]; + char ntlm_timeout[32]; + char* proc_parameter[6]; + + if (name == NULL || password == NULL || domainname == NULL || groupname == NULL) + { + Debug("Sam.c - SmbAuthenticate - wrong password parameter\n"); + return false; + } + + if (password[0] == '\0' && (challenge8 == NULL || MsChapV2_ClientResponse == NULL || nt_pw_hash_hash == NULL)) + { + Debug("Sam.c - SmbAuthenticate - wrong MsCHAPv2 parameter\n"); + return false; + } + + Zero(buffer, sizeof(buffer)); + + // Truncate string if unsafe char + EnSafeStr(domainname, '\0'); + + if (strlen(domainname) > 255) + { + // there is no domainname longer then 255 chars! + // http://tools.ietf.org/html/rfc1035 section 2.3.4 + domainname[255] = '\0'; + } + + // set timeout to 15 minutes even if timeout is disabled, to prevent ntlm_auth from hung up + if (timeout <= 0 || timeout > 900) + { + timeout = 999; + } + + snprintf(ntlm_timeout, sizeof(ntlm_timeout), "%is", timeout); + Debug("Sam.c - timeout for ntlm_auth %s\n", ntlm_timeout); + + proc_parameter[0] = "timeout"; + proc_parameter[1] = ntlm_timeout; + proc_parameter[2] = "ntlm_auth"; + proc_parameter[3] = "--helper-protocol=ntlm-server-1"; + proc_parameter[4] = 0; + + if (strlen(groupname) > 1) + { + // DNS Name 255 chars + OU names are limited to 64 characters + cmdline 32 + 1 + char requiremember[352]; + + // Truncate string if unsafe char + EnSafeStr(groupname, '\0'); + + snprintf(requiremember, sizeof(requiremember), "--require-membership-of=%s\\%s", domainname, groupname); + + proc_parameter[4] = requiremember; + proc_parameter[5] = 0; + } + + pid = OpenChildProcess("timeout", proc_parameter, fds); + + if (pid < 0) + { + Debug("Sam.c - SmbCheckLogon - error fork child process (ntlm_auth)\n"); + return false; + } + + out = fdopen(fds[1], "w"); + if (out == 0) + { + CloseChildProcess(pid, fds); + + Debug("Sam.c - cant open out pipe (ntlm_auth)\n"); + return false; + } + + in = fdopen(fds[0], "r"); + if (in == 0) + { + fclose(out); + CloseChildProcess(pid, fds); + + Debug("Sam.c - cant open in pipe (ntlm_auth)\n"); + return false; + } + + if (base64_enc_len(strlen(name)) < sizeof(buffer)-1 && + base64_enc_len(strlen(password)) < sizeof(buffer)-1 && + base64_enc_len(strlen(domainname)) < sizeof(buffer)-1) + { + char answer[300]; + + unsigned int end = B64_Encode(buffer, name, strlen(name)); + buffer[end] = '\0'; + fputs("Username:: ", out); + fputs(buffer, out); + fputs("\n", out); + Debug("Username: %s\n", buffer); + buffer[0] = 0; + + end = B64_Encode(buffer, domainname, strlen(domainname)); + buffer[end] = '\0'; + fputs("NT-Domain:: ", out); + fputs(buffer, out); + fputs("\n", out); + Debug("NT-Domain: %s\n", buffer); + buffer[0] = 0; + + if (password[0] != '\0') + { + Debug("Password authentication\n"); + end = B64_Encode(buffer, password, strlen(password)); + buffer[end] = '\0'; + fputs("Password:: ", out); + fputs(buffer, out); + fputs("\n", out); + Debug("Password: %s\n", buffer); + buffer[0] = 0; + } + else + { + char* mschapv2_client_response; + char* base64_challenge8; + + Debug("MsChapV2 authentication\n"); + mschapv2_client_response = CopyBinToStr(MsChapV2_ClientResponse, 24); + end = B64_Encode(buffer, mschapv2_client_response, 48); + buffer[end] = '\0'; + fputs("NT-Response:: ", out); + fputs(buffer, out); + fputs("\n", out); + Debug("NT-Response:: %s\n", buffer); + buffer[0] = 0; + Free(mschapv2_client_response); + + base64_challenge8 = CopyBinToStr(challenge8, 8); + end = B64_Encode(buffer, base64_challenge8 , 16); + buffer[end] = '\0'; + fputs("LANMAN-Challenge:: ", out); + fputs(buffer, out); + fputs("\n", out); + Debug("LANMAN-Challenge:: %s\n", buffer); + buffer[0] = 0; + Free(base64_challenge8); + + fputs("Request-User-Session-Key: Yes\n", out); + } + + // Start authentication + fputs( ".\n", out ); + fflush (out); + // Request send! + + Zero(answer, sizeof(answer)); + + while (fgets(answer, sizeof(answer)-1, in)) + { + char* response_parameter; + + if (strncmp(answer, ".\n", sizeof(answer)-1 ) == 0) + { + break; + } + + /* Indicates a base64 encoded structure */ + response_parameter = strstr(answer, ":: "); + if (!response_parameter) { + char* newline; + + response_parameter = strstr(answer, ": "); + + if (!response_parameter) { + continue; + } + + response_parameter[0] ='\0'; + response_parameter++; + response_parameter[0] ='\0'; + response_parameter++; + + newline = strstr(response_parameter, "\n"); + if( newline ) + newline[0] = '\0'; + } else { + response_parameter[0] ='\0'; + response_parameter++; + response_parameter[0] ='\0'; + response_parameter++; + response_parameter[0] ='\0'; + response_parameter++; + + end = Decode64(response_parameter, response_parameter); + response_parameter[end] = '\0'; + } + + if (strncmp(answer, "Authenticated", sizeof(answer)-1 ) == 0) + { + if (strcmp(response_parameter, "Yes") == 0) + { + Debug("Authenticated!\n"); + auth = true; + } + else if (strcmp(response_parameter, "No") == 0) + { + Debug("Authentication failed!\n"); + auth = false; + } + } + else if (strncmp(answer, "User-Session-Key", sizeof(answer)-1 ) == 0) + { + if (nt_pw_hash_hash != NULL) + { + BUF* Buf = StrToBin(response_parameter); + Copy(nt_pw_hash_hash, Buf->Buf, 16); + FreeBuf(Buf); + } + } + } + } + + fclose(in); + fclose(out); + + CloseChildProcess(pid, fds); + + return auth; +} + + +bool SmbCheckLogon(char* name, char* password, char* domainname, char* groupname, UINT timeout) +{ + return SmbAuthenticate(name, password, domainname, groupname, timeout, NULL, NULL, NULL); +} + +bool SmbPerformMsChapV2Auth(char* name, char* domainname, char* groupname, UCHAR* challenge8, UCHAR* MsChapV2_ClientResponse, UCHAR* nt_pw_hash_hash, UINT timeout) +{ + return SmbAuthenticate(name, "", domainname, groupname, timeout, challenge8, MsChapV2_ClientResponse, nt_pw_hash_hash); +} + // Password encryption void SecurePassword(void *secure_password, void *password, void *random) { @@ -164,6 +505,8 @@ bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *p { bool b = false; wchar_t *name = NULL; + wchar_t *groupname = NULL; + UINT timeout = 90; bool auth_by_nt = false; HUB *h; // Validate arguments @@ -216,6 +559,14 @@ bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *p { name = CopyUniStr(auth->NtUsername); } + + groupname = CopyStrToUni(u->GroupName); + + if (u->Policy) + { + timeout = u->Policy->TimeOut; + } + auth_by_nt = true; } } @@ -264,7 +615,7 @@ bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *p } else { - // NT authentication (Not available for non-Win32) + // NT authentication #ifdef OS_WIN32 IPC_MSCHAP_V2_AUTHINFO mschap; Unlock(hub->lock); @@ -303,11 +654,60 @@ bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *p Lock(hub->lock); #else // OS_WIN32 - // Nothing to do other than Win32 -#endif // OS_WIN32 + // Unix / Samba Winbind + + IPC_MSCHAP_V2_AUTHINFO mschap; + Unlock(hub->lock); + + char nt_name[MAX_SIZE]; + char nt_username[MAX_SIZE]; + char nt_groupname[MAX_SIZE]; + char nt_domainname[MAX_SIZE]; + UCHAR challenge8[8]; + UCHAR nt_pw_hash_hash[16]; + + nt_groupname[0] = 0; + + UniToStr(nt_name, sizeof(nt_name), name); + + if (groupname != NULL) + UniToStr(nt_groupname, sizeof(nt_groupname), groupname); + + ParseNtUsername(nt_name, nt_username, sizeof(nt_username), nt_domainname, sizeof(nt_domainname), false); + + if (ParseAndExtractMsChapV2InfoFromPassword(&mschap, password) == false) + { + // Plaintext password authentication + b = SmbCheckLogon(nt_username, password, nt_domainname, nt_groupname, timeout); + } + else + { + // MS-CHAPv2 authentication + MsChapV2_GenerateChallenge8(challenge8, mschap.MsChapV2_ClientChallenge, + mschap.MsChapV2_ServerChallenge, + mschap.MsChapV2_PPPUsername); + + Debug("MsChapV2_PPPUsername = %s, nt_name = %s\n", mschap.MsChapV2_PPPUsername, nt_name); + + b = SmbPerformMsChapV2Auth(nt_username, nt_domainname, nt_groupname, challenge8, mschap.MsChapV2_ClientResponse, nt_pw_hash_hash, timeout); + + if (b) + { + if (mschap_v2_server_response_20 != NULL) + { + MsChapV2Server_GenerateResponse(mschap_v2_server_response_20, nt_pw_hash_hash, + mschap.MsChapV2_ClientResponse, challenge8); + } + } + } + + Lock(hub->lock); +#endif // OS_WIN32 / OS_LINUX } // Memory release + if( groupname != NULL ) + Free(groupname); Free(name); } diff --git a/src/Mayaqua/MayaType.h b/src/Mayaqua/MayaType.h index bf4af8bc..2151e5d5 100644 --- a/src/Mayaqua/MayaType.h +++ b/src/Mayaqua/MayaType.h @@ -239,6 +239,14 @@ typedef int (COMPARE)(void *p1, void *p2); // Type declaration // +// PID type +#ifdef OS_UNIX +typedef int PID; +#endif // OS_UNIX +#ifdef OS_WIN32 +typedef unsigned long PID; +#endif // WINDOWS_H + // bool type #ifndef WINDOWS_H typedef unsigned int BOOL;