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
34 #define WIN32_NO_STATUS
40 #include "wine/debug.h"
43 extern char **environ
;
45 WINE_DEFAULT_DEBUG_CHANNEL(ntlm
);
46 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
48 #define INITIAL_BUFFER_SIZE 200
57 static SECURITY_STATUS
read_line( struct ntlm_ctx
*ctx
, unsigned int *offset
)
60 struct com_buf
*com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
64 if (!(com_buf
= malloc( sizeof(*com_buf
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
65 if (!(com_buf
->buffer
= malloc( INITIAL_BUFFER_SIZE
)))
68 return SEC_E_INSUFFICIENT_MEMORY
;
70 com_buf
->size
= INITIAL_BUFFER_SIZE
;
72 ctx
->com_buf
= (ULONG_PTR
)com_buf
;
78 if (com_buf
->offset
+ INITIAL_BUFFER_SIZE
> com_buf
->size
)
80 char *buf
= realloc( com_buf
->buffer
, com_buf
->size
+ INITIAL_BUFFER_SIZE
);
81 if (!buf
) return SEC_E_INSUFFICIENT_MEMORY
;
82 com_buf
->size
+= INITIAL_BUFFER_SIZE
;
83 com_buf
->buffer
= buf
;
85 size
= read( ctx
->pipe_in
, com_buf
->buffer
+ com_buf
->offset
, com_buf
->size
- com_buf
->offset
);
86 if (size
<= 0) return SEC_E_INTERNAL_ERROR
;
88 com_buf
->offset
+= size
;
89 newline
= memchr( com_buf
->buffer
, '\n', com_buf
->offset
);
92 /* if there's a newline character, and we read more than that newline, we have to store the offset so we can
93 preserve the additional data */
94 if (newline
!= com_buf
->buffer
+ com_buf
->offset
) *offset
= (com_buf
->buffer
+ com_buf
->offset
) - (newline
+ 1);
101 static NTSTATUS
ntlm_chat( void *args
)
103 const struct chat_params
*params
= args
;
104 struct ntlm_ctx
*ctx
= params
->ctx
;
105 struct com_buf
*com_buf
;
106 SECURITY_STATUS status
= SEC_E_OK
;
109 write( ctx
->pipe_out
, params
->buf
, strlen(params
->buf
) );
110 write( ctx
->pipe_out
, "\n", 1 );
112 if ((status
= read_line( ctx
, &offset
)) != SEC_E_OK
) return status
;
113 com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
114 *params
->retlen
= strlen( com_buf
->buffer
);
116 if (*params
->retlen
> params
->buflen
) return SEC_E_BUFFER_TOO_SMALL
;
117 if (*params
->retlen
< 2) return SEC_E_ILLEGAL_MESSAGE
;
118 if (!strncmp( com_buf
->buffer
, "ERR", 3 )) return SEC_E_INVALID_TOKEN
;
120 memcpy( params
->buf
, com_buf
->buffer
, *params
->retlen
+ 1 );
122 if (!offset
) com_buf
->offset
= 0;
125 memmove( com_buf
->buffer
, com_buf
->buffer
+ com_buf
->offset
, offset
);
126 com_buf
->offset
= offset
;
132 static NTSTATUS
ntlm_cleanup( void *args
)
134 struct ntlm_ctx
*ctx
= args
;
135 struct com_buf
*com_buf
= (struct com_buf
*)(ULONG_PTR
)ctx
->com_buf
;
137 if (!ctx
|| (ctx
->mode
!= MODE_CLIENT
&& ctx
->mode
!= MODE_SERVER
)) return STATUS_INVALID_HANDLE
;
138 ctx
->mode
= MODE_INVALID
;
140 /* closing stdin will terminate ntlm_auth */
141 close( ctx
->pipe_out
);
142 close( ctx
->pipe_in
);
144 if (ctx
->pid
> 0) /* reap child */
148 ret
= waitpid( ctx
->pid
, NULL
, 0 );
149 } while (ret
< 0 && errno
== EINTR
);
152 if (com_buf
) free( com_buf
->buffer
);
154 return STATUS_SUCCESS
;
157 static NTSTATUS
ntlm_fork( void *args
)
159 const struct fork_params
*params
= args
;
160 struct ntlm_ctx
*ctx
= params
->ctx
;
161 posix_spawn_file_actions_t file_actions
;
162 int pipe_in
[2], pipe_out
[2];
165 if (pipe2( pipe_in
, O_CLOEXEC
) < 0)
168 if (pipe( pipe_in
) < 0 ) return SEC_E_INTERNAL_ERROR
;
169 fcntl( pipe_in
[0], F_SETFD
, FD_CLOEXEC
);
170 fcntl( pipe_in
[1], F_SETFD
, FD_CLOEXEC
);
173 if (pipe2( pipe_out
, O_CLOEXEC
) < 0)
176 if (pipe( pipe_out
) < 0)
180 return SEC_E_INTERNAL_ERROR
;
182 fcntl( pipe_out
[0], F_SETFD
, FD_CLOEXEC
);
183 fcntl( pipe_out
[1], F_SETFD
, FD_CLOEXEC
);
186 posix_spawn_file_actions_init( &file_actions
);
188 posix_spawn_file_actions_adddup2( &file_actions
, pipe_out
[0], 0 );
189 posix_spawn_file_actions_addclose( &file_actions
, pipe_out
[0] );
190 posix_spawn_file_actions_addclose( &file_actions
, pipe_out
[1] );
192 posix_spawn_file_actions_adddup2( &file_actions
, pipe_in
[1], 1 );
193 posix_spawn_file_actions_addclose( &file_actions
, pipe_in
[0] );
194 posix_spawn_file_actions_addclose( &file_actions
, pipe_in
[1] );
196 if (posix_spawnp( &ctx
->pid
, params
->argv
[0], &file_actions
, NULL
, params
->argv
, environ
))
199 write( pipe_in
[1], "BH\n", 3 );
202 ctx
->pipe_in
= pipe_in
[0];
204 ctx
->pipe_out
= pipe_out
[1];
205 close( pipe_out
[0] );
207 posix_spawn_file_actions_destroy( &file_actions
);
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)
229 if ((newline
= memchr( buf
, '\n', len
))) *newline
= 0;
232 TRACE( "detected ntlm_auth version %s\n", debugstr_a(buf
) );
233 status
= STATUS_SUCCESS
;
236 if (status
) ERR_(winediag
)( "ntlm_auth was not found. Make sure that ntlm_auth >= 3.0.25 is in your path. "
237 "Usually, you can find it in the winbind package of your distribution.\n" );
238 ntlm_cleanup( &ctx
);
242 const unixlib_entry_t __wine_unix_call_funcs
[] =
250 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs
) == unix_funcs_count
);
256 static NTSTATUS
wow64_ntlm_chat( void *args
)
264 } const *params32
= args
;
266 struct chat_params params
=
268 ULongToPtr(params32
->ctx
),
269 ULongToPtr(params32
->buf
),
271 ULongToPtr(params32
->retlen
)
274 return ntlm_chat( ¶ms
);
277 static NTSTATUS
wow64_ntlm_fork( void *args
)
283 } const *params32
= args
;
285 struct fork_params params
;
286 PTR32
*argv32
= ULongToPtr(params32
->argv
);
291 while (argv32
[argc
]) argc
++;
292 argv
= malloc( (argc
+ 1) * sizeof(*argv
) );
293 for (i
= 0; i
<= argc
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
295 params
.ctx
= ULongToPtr(params32
->ctx
);
297 ret
= ntlm_fork( ¶ms
);
302 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
310 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs
) == unix_funcs_count
);