2 * Unix interface for ntlm_auth
4 * Copyright 2005, 2006 Kai Blin
5 * Copyright 2021 Hans Leidekker for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #define WIN32_NO_STATUS
39 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ntlm
);
43 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
45 #define INITIAL_BUFFER_SIZE 200
54 static SECURITY_STATUS
read_line( struct ntlm_ctx
*ctx
, unsigned int *offset
)
57 struct com_buf
*com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
61 if (!(com_buf
= malloc( sizeof(*com_buf
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
62 if (!(com_buf
->buffer
= malloc( INITIAL_BUFFER_SIZE
)))
65 return SEC_E_INSUFFICIENT_MEMORY
;
67 com_buf
->size
= INITIAL_BUFFER_SIZE
;
69 ctx
->com_buf
= (ULONG_PTR
)com_buf
;
75 if (com_buf
->offset
+ INITIAL_BUFFER_SIZE
> com_buf
->size
)
77 char *buf
= realloc( com_buf
->buffer
, com_buf
->size
+ INITIAL_BUFFER_SIZE
);
78 if (!buf
) return SEC_E_INSUFFICIENT_MEMORY
;
79 com_buf
->size
+= INITIAL_BUFFER_SIZE
;
80 com_buf
->buffer
= buf
;
82 size
= read( ctx
->pipe_in
, com_buf
->buffer
+ com_buf
->offset
, com_buf
->size
- com_buf
->offset
);
83 if (size
<= 0) return SEC_E_INTERNAL_ERROR
;
85 com_buf
->offset
+= size
;
86 newline
= memchr( com_buf
->buffer
, '\n', com_buf
->offset
);
89 /* if there's a newline character, and we read more than that newline, we have to store the offset so we can
90 preserve the additional data */
91 if (newline
!= com_buf
->buffer
+ com_buf
->offset
) *offset
= (com_buf
->buffer
+ com_buf
->offset
) - (newline
+ 1);
98 static NTSTATUS
ntlm_chat( void *args
)
100 const struct chat_params
*params
= args
;
101 struct ntlm_ctx
*ctx
= params
->ctx
;
102 struct com_buf
*com_buf
;
103 SECURITY_STATUS status
= SEC_E_OK
;
106 write( ctx
->pipe_out
, params
->buf
, strlen(params
->buf
) );
107 write( ctx
->pipe_out
, "\n", 1 );
109 if ((status
= read_line( ctx
, &offset
)) != SEC_E_OK
) return status
;
110 com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
111 *params
->retlen
= strlen( com_buf
->buffer
);
113 if (*params
->retlen
> params
->buflen
) return SEC_E_BUFFER_TOO_SMALL
;
114 if (*params
->retlen
< 2) return SEC_E_ILLEGAL_MESSAGE
;
115 if (!strncmp( com_buf
->buffer
, "ERR", 3 )) return SEC_E_INVALID_TOKEN
;
117 memcpy( params
->buf
, com_buf
->buffer
, *params
->retlen
+ 1 );
119 if (!offset
) com_buf
->offset
= 0;
122 memmove( com_buf
->buffer
, com_buf
->buffer
+ com_buf
->offset
, offset
);
123 com_buf
->offset
= offset
;
129 static NTSTATUS
ntlm_cleanup( void *args
)
131 struct ntlm_ctx
*ctx
= args
;
132 struct com_buf
*com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
134 if (!ctx
|| (ctx
->mode
!= MODE_CLIENT
&& ctx
->mode
!= MODE_SERVER
)) return STATUS_INVALID_HANDLE
;
135 ctx
->mode
= MODE_INVALID
;
137 /* closing stdin will terminate ntlm_auth */
138 close( ctx
->pipe_out
);
139 close( ctx
->pipe_in
);
141 if (ctx
->pid
> 0) /* reap child */
145 ret
= waitpid( ctx
->pid
, NULL
, 0 );
146 } while (ret
< 0 && errno
== EINTR
);
149 if (com_buf
) free( com_buf
->buffer
);
151 return STATUS_SUCCESS
;
154 static NTSTATUS
ntlm_fork( void *args
)
156 const struct fork_params
*params
= args
;
157 struct ntlm_ctx
*ctx
= params
->ctx
;
158 int pipe_in
[2], pipe_out
[2];
161 if (pipe2( pipe_in
, O_CLOEXEC
) < 0)
164 if (pipe( pipe_in
) < 0 ) return SEC_E_INTERNAL_ERROR
;
165 fcntl( pipe_in
[0], F_SETFD
, FD_CLOEXEC
);
166 fcntl( pipe_in
[1], F_SETFD
, FD_CLOEXEC
);
169 if (pipe2( pipe_out
, O_CLOEXEC
) < 0)
172 if (pipe( pipe_out
) < 0)
176 return SEC_E_INTERNAL_ERROR
;
178 fcntl( pipe_out
[0], F_SETFD
, FD_CLOEXEC
);
179 fcntl( pipe_out
[1], F_SETFD
, FD_CLOEXEC
);
182 if (!(ctx
->pid
= fork())) /* child */
184 dup2( pipe_out
[0], 0 );
185 close( pipe_out
[0] );
186 close( pipe_out
[1] );
188 dup2( pipe_in
[1], 1 );
192 execvp( params
->argv
[0], params
->argv
);
194 write( 1, "BH\n", 3 );
199 ctx
->pipe_in
= pipe_in
[0];
201 ctx
->pipe_out
= pipe_out
[1];
202 close( pipe_out
[0] );
208 #define NTLM_AUTH_MAJOR_VERSION 3
209 #define NTLM_AUTH_MINOR_VERSION 0
210 #define NTLM_AUTH_MICRO_VERSION 25
212 static NTSTATUS
ntlm_check_version( void *args
)
214 struct ntlm_ctx ctx
= { 0 };
215 char *argv
[3], buf
[80];
216 NTSTATUS status
= STATUS_DLL_NOT_FOUND
;
217 struct fork_params params
= { &ctx
, argv
};
220 argv
[0] = (char *)"ntlm_auth";
221 argv
[1] = (char *)"--version";
223 if (ntlm_fork( ¶ms
) != SEC_E_OK
) return status
;
225 if ((len
= read( ctx
.pipe_in
, buf
, sizeof(buf
) - 1 )) > 8)
228 int major
= 0, minor
= 0, micro
= 0;
230 if ((newline
= memchr( buf
, '\n', len
))) *newline
= 0;
233 if (sscanf( buf
, "Version %d.%d.%d", &major
, &minor
, µ
) == 3)
235 if (((major
> NTLM_AUTH_MAJOR_VERSION
) ||
236 (major
== NTLM_AUTH_MAJOR_VERSION
&& minor
> NTLM_AUTH_MINOR_VERSION
) ||
237 (major
== NTLM_AUTH_MAJOR_VERSION
&& minor
== NTLM_AUTH_MINOR_VERSION
&&
238 micro
>= NTLM_AUTH_MICRO_VERSION
)))
240 TRACE( "detected ntlm_auth version %d.%d.%d\n", major
, minor
, micro
);
241 status
= STATUS_SUCCESS
;
246 if (status
) ERR_(winediag
)( "ntlm_auth was not found or is outdated. "
247 "Make sure that ntlm_auth >= %d.%d.%d is in your path. "
248 "Usually, you can find it in the winbind package of your distribution.\n",
249 NTLM_AUTH_MAJOR_VERSION
, NTLM_AUTH_MINOR_VERSION
, NTLM_AUTH_MICRO_VERSION
);
250 ntlm_cleanup( &ctx
);
254 const unixlib_entry_t __wine_unix_call_funcs
[] =
266 static NTSTATUS
wow64_ntlm_chat( void *args
)
274 } const *params32
= args
;
276 struct chat_params params
=
278 ULongToPtr(params32
->ctx
),
279 ULongToPtr(params32
->buf
),
281 ULongToPtr(params32
->retlen
)
284 return ntlm_chat( ¶ms
);
287 static NTSTATUS
wow64_ntlm_fork( void *args
)
293 } const *params32
= args
;
295 struct fork_params params
;
296 PTR32
*argv32
= ULongToPtr(params32
->argv
);
301 while (argv32
[argc
]) argc
++;
302 argv
= malloc( (argc
+ 1) * sizeof(*argv
) );
303 for (i
= 0; i
<= argc
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
305 params
.ctx
= ULongToPtr(params32
->ctx
);
307 ret
= ntlm_fork( ¶ms
);
312 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =