2 * (C) 2002,2005 Guido Serassio <guido.serassio@acmeconsulting.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
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.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
17 typedef unsigned char uchar
;
27 /* returns 1 on success, 0 on failure */
29 Valid_Group(char *UserName
, char *Group
)
32 WCHAR wszUserName
[UNLEN
+1]; // Unicode user name
33 WCHAR wszGroup
[GNLEN
+1]; // Unicode Group
35 LPLOCALGROUP_USERS_INFO_0 pBuf
= NULL
;
36 LPLOCALGROUP_USERS_INFO_0 pTmpBuf
;
38 DWORD dwFlags
= LG_INCLUDE_INDIRECT
;
39 DWORD dwPrefMaxLen
= -1;
40 DWORD dwEntriesRead
= 0;
41 DWORD dwTotalEntries
= 0;
42 NET_API_STATUS nStatus
;
44 DWORD dwTotalCount
= 0;
46 /* Convert ANSI User Name and Group to Unicode */
48 MultiByteToWideChar(CP_ACP
, 0, UserName
,
49 strlen(UserName
) + 1, wszUserName
,
50 sizeof(wszUserName
) / sizeof(wszUserName
[0]));
51 MultiByteToWideChar(CP_ACP
, 0, Group
,
52 strlen(Group
) + 1, wszGroup
, sizeof(wszGroup
) / sizeof(wszGroup
[0]));
55 * Call the NetUserGetLocalGroups function
56 * specifying information level 0.
58 * The LG_INCLUDE_INDIRECT flag specifies that the
59 * function should also return the names of the local
60 * groups in which the user is indirectly a member.
62 nStatus
= NetUserGetLocalGroups(NULL
,
66 (LPBYTE
*) & pBuf
, dwPrefMaxLen
, &dwEntriesRead
, &dwTotalEntries
);
68 * If the call succeeds,
70 if (nStatus
== NERR_Success
) {
71 if ((pTmpBuf
= pBuf
) != NULL
) {
72 for (i
= 0; i
< dwEntriesRead
; i
++) {
73 if (pTmpBuf
== NULL
) {
77 if (wcscmp(pTmpBuf
->lgrui0_name
, wszGroup
) == 0) {
88 * Free the allocated memory.
91 NetApiBufferFree(pBuf
);
96 char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr
)
101 len
= LsaStr
.Length
/sizeof(WCHAR
) + 1;
103 /* allocate buffer for str + null termination */
105 target
= (char *)xmalloc(len
);
109 /* copy unicode buffer */
110 WideCharToMultiByte(CP_ACP
, 0, LsaStr
.Buffer
, LsaStr
.Length
, target
, len
, NULL
, NULL
);
112 /* add null termination */
113 target
[len
-1] = '\0';
118 char * GetDomainName(void)
121 LSA_HANDLE PolicyHandle
;
122 LSA_OBJECT_ATTRIBUTES ObjectAttributes
;
124 PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo
;
125 PWKSTA_INFO_100 pwkiWorkstationInfo
;
127 char * DomainName
= NULL
;
130 * Always initialize the object attributes to all zeroes.
132 memset(&ObjectAttributes
, '\0', sizeof(ObjectAttributes
));
135 * You need the local workstation name. Use NetWkstaGetInfo at level
136 * 100 to retrieve a WKSTA_INFO_100 structure.
138 * The wki100_computername field contains a pointer to a UNICODE
139 * string containing the local computer name.
141 netret
= NetWkstaGetInfo(NULL
, 100, (LPBYTE
*)&pwkiWorkstationInfo
);
142 if (netret
== NERR_Success
) {
144 * We have the workstation name in:
145 * pwkiWorkstationInfo->wki100_computername
147 * Next, open the policy object for the local system using
148 * the LsaOpenPolicy function.
150 status
= LsaOpenPolicy(
153 GENERIC_READ
| POLICY_VIEW_LOCAL_INFORMATION
,
161 debug("OpenPolicy Error: %ld\n", status
);
165 * You have a handle to the policy object. Now, get the
166 * domain information using LsaQueryInformationPolicy.
168 status
= LsaQueryInformationPolicy(PolicyHandle
,
169 PolicyPrimaryDomainInformation
,
170 (void **)&ppdiDomainInfo
);
172 debug("LsaQueryInformationPolicy Error: %ld\n", status
);
175 /* Get name in useable format */
176 DomainName
= AllocStrFromLSAStr(ppdiDomainInfo
->Name
);
179 * Check the Sid pointer, if it is null, the
180 * workstation is either a stand-alone computer
181 * or a member of a workgroup.
183 if (ppdiDomainInfo
->Sid
) {
186 * Member of a domain. Display it in debug mode.
188 debug("Member of Domain %s\n",DomainName
);
196 * Clean up all the memory buffers created by the LSA and
199 NetApiBufferFree(pwkiWorkstationInfo
);
200 LsaFreeMemory((LPVOID
)ppdiDomainInfo
);
202 debug("NetWkstaGetInfo Error: %ld\n", netret
);
210 /* returns NULL on failure, or a pointer to
211 * the user's credentials (domain\\username)
212 * upon success. WARNING. It's pointing to static storage.
213 * In case of problem sets as side-effect ntlm_errno to one of the
214 * codes defined in ntlm.h
217 ntlm_check_auth(ntlm_authenticate
* auth
, int auth_length
)
220 char domain
[DNLEN
+1];
222 static char credentials
[DNLEN
+UNLEN
+2]; /* we can afford to waste */
226 if (!NTLM_LocalCall
) {
228 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->domain
);
230 if (tmp
.str
== NULL
|| tmp
.l
== 0) {
231 debug("No domain supplied. Returning no-auth\n");
232 ntlm_errno
= NTLM_BAD_REQUEST
;
236 /* copy unicode buffer */
237 WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
) tmp
.str
, tmp
.l
, domain
, DNLEN
, NULL
, NULL
);
238 /* add null termination */
239 domain
[tmp
.l
/ sizeof(WCHAR
)] = '\0';
242 debug("Domain string exceeds %d bytes, rejecting\n", DNLEN
);
243 ntlm_errno
= NTLM_BAD_REQUEST
;
246 memcpy(domain
, tmp
.str
, tmp
.l
);
247 domain
[tmp
.l
] = '\0';
249 tmp
= ntlm_fetch_string((char *) auth
, auth_length
, &auth
->user
);
250 if (tmp
.str
== NULL
|| tmp
.l
== 0) {
251 debug("No username supplied. Returning no-auth\n");
252 ntlm_errno
= NTLM_BAD_REQUEST
;
256 /* copy unicode buffer */
257 WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
) tmp
.str
, tmp
.l
, user
, UNLEN
, NULL
, NULL
);
258 /* add null termination */
259 user
[tmp
.l
/ sizeof(WCHAR
)] = '\0';
262 debug("Username string exceeds %d bytes, rejecting\n", UNLEN
);
263 ntlm_errno
= NTLM_BAD_REQUEST
;
266 memcpy(user
, tmp
.str
, tmp
.l
);
269 debug("checking domain: '%s', user: '%s'\n", domain
, user
);
272 debug("checking local user\n");
274 rv
= SSP_ValidateNTLMCredentials(auth
, auth_length
, credentials
);
276 debug("Login attempt had result %d\n", rv
);
278 if (!rv
) { /* failed */
279 ntlm_errno
= NTLM_SSPI_ERROR
;
283 if (UseAllowedGroup
) {
284 if (!Valid_Group(credentials
, NTAllowedGroup
)) {
285 ntlm_errno
= NTLM_BAD_NTGROUP
;
286 debug("User %s not in allowed Group %s\n", credentials
, NTAllowedGroup
);
290 if (UseDisallowedGroup
) {
291 if (Valid_Group(credentials
, NTDisAllowedGroup
)) {
292 ntlm_errno
= NTLM_BAD_NTGROUP
;
293 debug("User %s is in denied Group %s\n", credentials
, NTDisAllowedGroup
);
298 debug("credentials: %s\n", credentials
);
304 ntlm_make_negotiate(void)
308 memset(&ne
, 0, sizeof(ntlm_negotiate
)); /* reset */
309 memcpy(ne
.signature
, "NTLMSSP", 8); /* set the signature */
310 ne
.type
= le32toh(NTLM_NEGOTIATE
); /* this is a challenge */
312 NEGOTIATE_ALWAYS_SIGN
|
318 encoded
= base64_encode_bin((char *) &ne
, NEGOTIATE_LENGTH
);
319 debug("Negotiate packet not supplied - self generated\n");
324 void hex_dump(void *data
, int size
)
326 /* dumps size bytes of *data to stdout. Looks like:
327 * [0000] 75 6E 6B 6E 6F 77 6E 20
328 * 30 FF 00 00 00 00 39 00 unknown 0.....9.
329 * (in a single line of course)
336 unsigned char *p
= data
;
339 char bytestr
[4] = {0};
340 char addrstr
[10] = {0};
341 char hexstr
[ 16*3 + 5] = {0};
342 char charstr
[16*1 + 5] = {0};
343 for (n
=1; n
<=size
; n
++) {
345 /* store address for this line */
346 snprintf(addrstr
, sizeof(addrstr
), "%.4x",
347 ((unsigned int)p
-(unsigned int)data
) );
351 if (xisalnum(c
) == 0) {
355 /* store hex str (for left side) */
356 snprintf(bytestr
, sizeof(bytestr
), "%02X ", *p
);
357 strncat(hexstr
, bytestr
, sizeof(hexstr
)-strlen(hexstr
)-1);
359 /* store char str (for right side) */
360 snprintf(bytestr
, sizeof(bytestr
), "%c", c
);
361 strncat(charstr
, bytestr
, sizeof(charstr
)-strlen(charstr
)-1);
365 fprintf(stderr
, "[%4.4s] %-50.50s %s\n", addrstr
, hexstr
, charstr
);
368 } else if (n
%8 == 0) {
369 /* half line: add whitespaces */
370 strncat(hexstr
, " ", sizeof(hexstr
)-strlen(hexstr
)-1);
371 strncat(charstr
, " ", sizeof(charstr
)-strlen(charstr
)-1);
376 if (strlen(hexstr
) > 0) {
377 /* print rest of buffer if not empty */
378 fprintf(stderr
, "[%4.4s] %-50.50s %s\n", addrstr
, hexstr
, charstr
);