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
47 static SECURITY_STATUS
read_line( struct ntlm_ctx
*ctx
, unsigned int *offset
)
53 if (!(ctx
->com_buf
= malloc( INITIAL_BUFFER_SIZE
)))
54 return SEC_E_INSUFFICIENT_MEMORY
;
55 ctx
->com_buf_size
= INITIAL_BUFFER_SIZE
;
56 ctx
->com_buf_offset
= 0;
62 if (ctx
->com_buf_offset
+ INITIAL_BUFFER_SIZE
> ctx
->com_buf_size
)
64 char *buf
= realloc( ctx
->com_buf
, ctx
->com_buf_size
+ INITIAL_BUFFER_SIZE
);
65 if (!buf
) return SEC_E_INSUFFICIENT_MEMORY
;
66 ctx
->com_buf_size
+= INITIAL_BUFFER_SIZE
;
69 size
= read( ctx
->pipe_in
, ctx
->com_buf
+ ctx
->com_buf_offset
, ctx
->com_buf_size
- ctx
->com_buf_offset
);
70 if (size
<= 0) return SEC_E_INTERNAL_ERROR
;
72 ctx
->com_buf_offset
+= size
;
73 newline
= memchr( ctx
->com_buf
, '\n', ctx
->com_buf_offset
);
76 /* if there's a newline character, and we read more than that newline, we have to store the offset so we can
77 preserve the additional data */
78 if (newline
!= ctx
->com_buf
+ ctx
->com_buf_offset
) *offset
= (ctx
->com_buf
+ ctx
->com_buf_offset
) - (newline
+ 1);
85 static NTSTATUS
ntlm_chat( void *args
)
87 struct chat_params
*params
= args
;
88 struct ntlm_ctx
*ctx
= params
->ctx
;
89 SECURITY_STATUS status
= SEC_E_OK
;
92 write( ctx
->pipe_out
, params
->buf
, strlen(params
->buf
) );
93 write( ctx
->pipe_out
, "\n", 1 );
95 if ((status
= read_line( ctx
, &offset
)) != SEC_E_OK
) return status
;
96 *params
->retlen
= strlen( ctx
->com_buf
);
98 if (*params
->retlen
> params
->buflen
) return SEC_E_BUFFER_TOO_SMALL
;
99 if (*params
->retlen
< 2) return SEC_E_ILLEGAL_MESSAGE
;
100 if (!strncmp( ctx
->com_buf
, "ERR", 3 )) return SEC_E_INVALID_TOKEN
;
102 memcpy( params
->buf
, ctx
->com_buf
, *params
->retlen
+ 1 );
104 if (!offset
) ctx
->com_buf_offset
= 0;
107 memmove( ctx
->com_buf
, ctx
->com_buf
+ ctx
->com_buf_offset
, offset
);
108 ctx
->com_buf_offset
= offset
;
114 static NTSTATUS
ntlm_cleanup( void *args
)
116 struct cleanup_params
*params
= args
;
117 struct ntlm_ctx
*ctx
= params
->ctx
;
119 if (!ctx
|| (ctx
->mode
!= MODE_CLIENT
&& ctx
->mode
!= MODE_SERVER
)) return STATUS_INVALID_HANDLE
;
120 ctx
->mode
= MODE_INVALID
;
122 /* closing stdin will terminate ntlm_auth */
123 close( ctx
->pipe_out
);
124 close( ctx
->pipe_in
);
126 if (ctx
->pid
> 0) /* reap child */
130 ret
= waitpid( ctx
->pid
, NULL
, 0 );
131 } while (ret
< 0 && errno
== EINTR
);
134 free( ctx
->com_buf
);
135 return STATUS_SUCCESS
;
138 static NTSTATUS
ntlm_fork( void *args
)
140 struct fork_params
*params
= args
;
141 struct ntlm_ctx
*ctx
= params
->ctx
;
142 int pipe_in
[2], pipe_out
[2];
145 if (pipe2( pipe_in
, O_CLOEXEC
) < 0)
148 if (pipe( pipe_in
) < 0 ) return SEC_E_INTERNAL_ERROR
;
149 fcntl( pipe_in
[0], F_SETFD
, FD_CLOEXEC
);
150 fcntl( pipe_in
[1], F_SETFD
, FD_CLOEXEC
);
153 if (pipe2( pipe_out
, O_CLOEXEC
) < 0)
156 if (pipe( pipe_out
) < 0)
160 return SEC_E_INTERNAL_ERROR
;
162 fcntl( pipe_out
[0], F_SETFD
, FD_CLOEXEC
);
163 fcntl( pipe_out
[1], F_SETFD
, FD_CLOEXEC
);
166 if (!(ctx
->pid
= fork())) /* child */
168 dup2( pipe_out
[0], 0 );
169 close( pipe_out
[0] );
170 close( pipe_out
[1] );
172 dup2( pipe_in
[1], 1 );
176 execvp( params
->argv
[0], params
->argv
);
178 write( 1, "BH\n", 3 );
183 ctx
->pipe_in
= pipe_in
[0];
185 ctx
->pipe_out
= pipe_out
[1];
186 close( pipe_out
[0] );
192 #define NTLM_AUTH_MAJOR_VERSION 3
193 #define NTLM_AUTH_MINOR_VERSION 0
194 #define NTLM_AUTH_MICRO_VERSION 25
196 static NTSTATUS
ntlm_check_version( void *args
)
198 struct ntlm_ctx ctx
= { 0 };
199 char *argv
[3], buf
[80];
200 NTSTATUS status
= STATUS_DLL_NOT_FOUND
;
201 struct fork_params params
= { &ctx
, argv
};
204 argv
[0] = (char *)"ntlm_auth";
205 argv
[1] = (char *)"--version";
207 if (ntlm_fork( ¶ms
) != SEC_E_OK
) return status
;
209 if ((len
= read( ctx
.pipe_in
, buf
, sizeof(buf
) - 1 )) > 8)
212 int major
= 0, minor
= 0, micro
= 0;
214 if ((newline
= memchr( buf
, '\n', len
))) *newline
= 0;
217 if (sscanf( buf
, "Version %d.%d.%d", &major
, &minor
, µ
) == 3)
219 if (((major
> NTLM_AUTH_MAJOR_VERSION
) ||
220 (major
== NTLM_AUTH_MAJOR_VERSION
&& minor
> NTLM_AUTH_MINOR_VERSION
) ||
221 (major
== NTLM_AUTH_MAJOR_VERSION
&& minor
== NTLM_AUTH_MINOR_VERSION
&&
222 micro
>= NTLM_AUTH_MICRO_VERSION
)))
224 TRACE( "detected ntlm_auth version %d.%d.%d\n", major
, minor
, micro
);
225 status
= STATUS_SUCCESS
;
230 if (status
) ERR_(winediag
)( "ntlm_auth was not found or is outdated. "
231 "Make sure that ntlm_auth >= %d.%d.%d is in your path. "
232 "Usually, you can find it in the winbind package of your distribution.\n",
233 NTLM_AUTH_MAJOR_VERSION
, NTLM_AUTH_MINOR_VERSION
, NTLM_AUTH_MICRO_VERSION
);
234 ntlm_cleanup( &ctx
);
238 const unixlib_entry_t __wine_unix_call_funcs
[] =