PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/helpers/ntlm_auth/mswin_sspi/libntlmssp.c

https://github.com/squid-cache/squid2
C | 393 lines | 256 code | 45 blank | 92 comment | 54 complexity | 88138c107c49b95e93b00c9f8698c861 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * (C) 2002 Guido Serassio <serassio@libero.it>
  3. * Based on previous work of Francesco Chemolli and Robert Collins
  4. * Distributed freely under the terms of the GNU General Public License,
  5. * version 2. See the file COPYING for licensing details
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. * You should have received a copy of the GNU General Public License
  12. * along with this program; if not, write to the Free Software
  13. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  14. */
  15. typedef unsigned char uchar;
  16. #include "util.h"
  17. #include "ntlm.h"
  18. #if HAVE_CTYPE_H
  19. #include <ctype.h>
  20. #endif
  21. #include <lm.h>
  22. #include <ntsecapi.h>
  23. /* returns 1 on success, 0 on failure */
  24. int
  25. Valid_Group(char *UserName, char *Group)
  26. {
  27. int result = FALSE;
  28. WCHAR wszUserName[UNLEN + 1]; // Unicode user name
  29. WCHAR wszGroup[GNLEN + 1]; // Unicode Group
  30. LPLOCALGROUP_USERS_INFO_0 pBuf;
  31. LPLOCALGROUP_USERS_INFO_0 pTmpBuf;
  32. DWORD dwLevel = 0;
  33. DWORD dwFlags = LG_INCLUDE_INDIRECT;
  34. DWORD dwPrefMaxLen = -1;
  35. DWORD dwEntriesRead = 0;
  36. DWORD dwTotalEntries = 0;
  37. NET_API_STATUS nStatus;
  38. DWORD i;
  39. DWORD dwTotalCount = 0;
  40. LPBYTE pBufTmp = NULL;
  41. /* Convert ANSI User Name and Group to Unicode */
  42. MultiByteToWideChar(CP_ACP, 0, UserName,
  43. strlen(UserName) + 1, wszUserName,
  44. sizeof(wszUserName) / sizeof(wszUserName[0]));
  45. MultiByteToWideChar(CP_ACP, 0, Group,
  46. strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0]));
  47. /*
  48. * Call the NetUserGetLocalGroups function
  49. * specifying information level 0.
  50. *
  51. * The LG_INCLUDE_INDIRECT flag specifies that the
  52. * function should also return the names of the local
  53. * groups in which the user is indirectly a member.
  54. */
  55. nStatus = NetUserGetLocalGroups(NULL,
  56. wszUserName,
  57. dwLevel,
  58. dwFlags,
  59. &pBufTmp,
  60. dwPrefMaxLen,
  61. &dwEntriesRead,
  62. &dwTotalEntries);
  63. pBuf = (LPLOCALGROUP_USERS_INFO_0) pBufTmp;
  64. /*
  65. * If the call succeeds,
  66. */
  67. if (nStatus == NERR_Success) {
  68. if ((pTmpBuf = pBuf) != NULL) {
  69. for (i = 0; i < dwEntriesRead; i++) {
  70. if (pTmpBuf == NULL) {
  71. result = FALSE;
  72. break;
  73. }
  74. if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) {
  75. result = TRUE;
  76. break;
  77. }
  78. pTmpBuf++;
  79. dwTotalCount++;
  80. }
  81. }
  82. } else
  83. result = FALSE;
  84. /*
  85. * Free the allocated memory.
  86. */
  87. if (pBuf != NULL)
  88. NetApiBufferFree(pBuf);
  89. return result;
  90. }
  91. char *
  92. AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr)
  93. {
  94. size_t len;
  95. static char *target;
  96. len = LsaStr.Length / sizeof(WCHAR) + 1;
  97. /* allocate buffer for str + null termination */
  98. safe_free(target);
  99. target = (char *) xmalloc(len);
  100. if (target == NULL)
  101. return NULL;
  102. /* copy unicode buffer */
  103. WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL);
  104. /* add null termination */
  105. target[len - 1] = '\0';
  106. return target;
  107. }
  108. char *
  109. GetDomainName(void)
  110. {
  111. LSA_HANDLE PolicyHandle;
  112. LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  113. NTSTATUS status;
  114. PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo = NULL;
  115. PWKSTA_INFO_100 pwkiWorkstationInfo;
  116. DWORD netret;
  117. char *DomainName = NULL;
  118. LPBYTE pwkiWorkstationInfoTmp;
  119. /*
  120. * Always initialize the object attributes to all zeroes.
  121. */
  122. memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes));
  123. /*
  124. * You need the local workstation name. Use NetWkstaGetInfo at level
  125. * 100 to retrieve a WKSTA_INFO_100 structure.
  126. *
  127. * The wki100_computername field contains a pointer to a UNICODE
  128. * string containing the local computer name.
  129. */
  130. netret = NetWkstaGetInfo(NULL, 100, &pwkiWorkstationInfoTmp);
  131. pwkiWorkstationInfo = (PWKSTA_INFO_100) pwkiWorkstationInfoTmp;
  132. if (netret == NERR_Success) {
  133. /*
  134. * We have the workstation name in:
  135. * pwkiWorkstationInfo->wki100_computername
  136. *
  137. * Next, open the policy object for the local system using
  138. * the LsaOpenPolicy function.
  139. */
  140. status = LsaOpenPolicy(
  141. NULL,
  142. &ObjectAttributes,
  143. GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION,
  144. &PolicyHandle
  145. );
  146. /*
  147. * Error checking.
  148. */
  149. if (status) {
  150. debug("OpenPolicy Error: %ld\n", status);
  151. } else {
  152. PVOID ppdiDomainInfoTmp;
  153. /*
  154. * You have a handle to the policy object. Now, get the
  155. * domain information using LsaQueryInformationPolicy.
  156. */
  157. status = LsaQueryInformationPolicy(PolicyHandle,
  158. PolicyPrimaryDomainInformation,
  159. &ppdiDomainInfoTmp);
  160. ppdiDomainInfo = (PPOLICY_PRIMARY_DOMAIN_INFO) ppdiDomainInfoTmp;
  161. if (status) {
  162. debug("LsaQueryInformationPolicy Error: %ld\n", status);
  163. } else {
  164. /* Get name in useable format */
  165. DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name);
  166. /*
  167. * Check the Sid pointer, if it is null, the
  168. * workstation is either a stand-alone computer
  169. * or a member of a workgroup.
  170. */
  171. if (ppdiDomainInfo->Sid) {
  172. /*
  173. * Member of a domain. Display it in debug mode.
  174. */
  175. debug("Member of Domain %s\n", DomainName);
  176. } else {
  177. DomainName = NULL;
  178. }
  179. }
  180. }
  181. /*
  182. * Clean up all the memory buffers created by the LSA and
  183. * Net* APIs.
  184. */
  185. NetApiBufferFree(pwkiWorkstationInfo);
  186. LsaFreeMemory((LPVOID) ppdiDomainInfo);
  187. } else
  188. debug("NetWkstaGetInfo Error: %ld\n", netret);
  189. return DomainName;
  190. }
  191. int ntlm_errno;
  192. /* returns NULL on failure, or a pointer to
  193. * the user's credentials (domain\\username)
  194. * upon success. WARNING. It's pointing to static storage.
  195. * In case of problem sets as side-effect ntlm_errno to one of the
  196. * codes defined in ntlm.h
  197. */
  198. char *
  199. ntlm_check_auth(ntlm_authenticate * auth, int auth_length)
  200. {
  201. int rv;
  202. char domain[DNLEN + 1];
  203. char user[UNLEN + 1];
  204. static char credentials[DNLEN + UNLEN + 2]; /* we can afford to waste */
  205. lstring tmp;
  206. if (!NTLM_LocalCall) {
  207. tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
  208. if (tmp.str == NULL || tmp.l == 0) {
  209. debug("No domain supplied. Returning no-auth\n");
  210. ntlm_errno = NTLM_BAD_REQUEST;
  211. return NULL;
  212. }
  213. if (Use_Unicode) {
  214. /* copy unicode buffer */
  215. WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, domain, DNLEN, NULL, NULL);
  216. /* add null termination */
  217. domain[tmp.l / sizeof(WCHAR)] = '\0';
  218. } else {
  219. if (tmp.l > DNLEN) {
  220. debug("Domain string exceeds %d bytes, rejecting\n", DNLEN);
  221. ntlm_errno = NTLM_BAD_REQUEST;
  222. return NULL;
  223. }
  224. memcpy(domain, tmp.str, tmp.l);
  225. domain[tmp.l] = '\0';
  226. }
  227. tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
  228. if (tmp.str == NULL || tmp.l == 0) {
  229. debug("No username supplied. Returning no-auth\n");
  230. ntlm_errno = NTLM_BAD_REQUEST;
  231. return NULL;
  232. }
  233. if (Use_Unicode) {
  234. /* copy unicode buffer */
  235. WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, user, UNLEN, NULL, NULL);
  236. /* add null termination */
  237. user[tmp.l / sizeof(WCHAR)] = '\0';
  238. } else {
  239. if (tmp.l > UNLEN) {
  240. debug("Username string exceeds %d bytes, rejecting\n", UNLEN);
  241. ntlm_errno = NTLM_BAD_REQUEST;
  242. return NULL;
  243. }
  244. memcpy(user, tmp.str, tmp.l);
  245. user[tmp.l] = '\0';
  246. }
  247. debug("checking domain: '%s', user: '%s'\n", domain, user);
  248. } else
  249. debug("checking local user\n");
  250. rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials);
  251. debug("Login attempt had result %d\n", rv);
  252. if (!rv) { /* failed */
  253. ntlm_errno = NTLM_SSPI_ERROR;
  254. return NULL;
  255. }
  256. if (UseAllowedGroup) {
  257. if (!Valid_Group(credentials, NTAllowedGroup)) {
  258. ntlm_errno = NTLM_BAD_NTGROUP;
  259. debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup);
  260. return NULL;
  261. }
  262. }
  263. if (UseDisallowedGroup) {
  264. if (Valid_Group(credentials, NTDisAllowedGroup)) {
  265. ntlm_errno = NTLM_BAD_NTGROUP;
  266. debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup);
  267. return NULL;
  268. }
  269. }
  270. debug("credentials: %s\n", credentials);
  271. return credentials;
  272. }
  273. const char *
  274. ntlm_make_negotiate(void)
  275. {
  276. ntlm_negotiate ne;
  277. const char *encoded;
  278. memset(&ne, 0, sizeof(ntlm_negotiate)); /* reset */
  279. memcpy(ne.signature, "NTLMSSP", 8); /* set the signature */
  280. ne.type = WSWAP(NTLM_NEGOTIATE); /* this is a challenge */
  281. ne.flags = WSWAP(
  282. NEGOTIATE_ALWAYS_SIGN |
  283. NEGOTIATE_USE_NTLM |
  284. NEGOTIATE_USE_LM |
  285. NEGOTIATE_ASCII |
  286. 0
  287. );
  288. encoded = base64_encode_bin((char *) &ne, NEGOTIATE_LENGTH);
  289. debug("Negotiate packet not supplied - self generated\n");
  290. return encoded;
  291. }
  292. void
  293. hex_dump(void *data, int size)
  294. {
  295. /* dumps size bytes of *data to stdout. Looks like:
  296. * [0000] 75 6E 6B 6E 6F 77 6E 20
  297. * 30 FF 00 00 00 00 39 00 unknown 0.....9.
  298. * (in a single line of course)
  299. */
  300. if (!data)
  301. return;
  302. if (debug_enabled) {
  303. unsigned char *p = data;
  304. unsigned char c;
  305. int n;
  306. char bytestr[4] =
  307. {0};
  308. char addrstr[10] =
  309. {0};
  310. char hexstr[16 * 3 + 5] =
  311. {0};
  312. char charstr[16 * 1 + 5] =
  313. {0};
  314. for (n = 1; n <= size; n++) {
  315. if (n % 16 == 1) {
  316. /* store address for this line */
  317. snprintf(addrstr, sizeof(addrstr), "%.4x",
  318. ((unsigned int) p - (unsigned int) data));
  319. }
  320. c = *p;
  321. if (xisalnum(c) == 0) {
  322. c = '.';
  323. }
  324. /* store hex str (for left side) */
  325. snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
  326. strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
  327. /* store char str (for right side) */
  328. snprintf(bytestr, sizeof(bytestr), "%c", c);
  329. strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);
  330. if (n % 16 == 0) {
  331. /* line completed */
  332. fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
  333. hexstr[0] = 0;
  334. charstr[0] = 0;
  335. } else if (n % 8 == 0) {
  336. /* half line: add whitespaces */
  337. strncat(hexstr, " ", sizeof(hexstr) - strlen(hexstr) - 1);
  338. strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
  339. }
  340. p++; /* next byte */
  341. }
  342. if (strlen(hexstr) > 0) {
  343. /* print rest of buffer if not empty */
  344. fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr);
  345. }
  346. }
  347. }