2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1997,
5 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
6 * Copyright (C) Paul Ashton 1997.
7 * Copyright (C) Jeremy Allison 1998.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 extern pstring global_myname;
28 extern fstring global_myworkgroup;
30 /****************************************************************************
31 Generate the next creds to use.
32 ****************************************************************************/
34 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
37 * Create the new client credentials.
40 cli->clnt_cred.timestamp.time = time(NULL);
42 memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
44 /* Calculate the new credentials. */
45 cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
46 new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
51 /****************************************************************************
52 do a LSA Logon Control2
53 ****************************************************************************/
54 BOOL cli_net_logon_ctrl2(struct cli_state *cli, NTSTATUS status_level)
58 NET_Q_LOGON_CTRL2 q_l;
61 prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
62 prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
64 /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
66 DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
67 global_myname, status_level));
69 /* store the parameters */
70 init_q_logon_ctrl2(&q_l, cli->srv_name_slash,
73 /* turn parameters into data stream */
74 if(!net_io_q_logon_ctrl2("", &q_l, &buf, 0)) {
75 DEBUG(0,("cli_net_logon_ctrl2: Error : failed to marshall NET_Q_LOGON_CTRL2 struct.\n"));
81 /* send the data on \PIPE\ */
82 if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
84 NET_R_LOGON_CTRL2 r_l;
87 * Unmarshall the return buffer.
89 ok = net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
91 if (ok && r_l.status != 0)
93 /* report error code */
94 DEBUG(0,("do_net_logon_ctrl2: Error %s\n", nt_errstr(r_l.status)));
95 cli->nt_error = r_l.status;
107 /****************************************************************************
110 Send the client credential, receive back a server credential.
111 Ensure that the server credential returned matches the session key
112 encrypt of the server challenge originally received. JRA.
113 ****************************************************************************/
115 NTSTATUS cli_net_auth2(struct cli_state *cli, uint16 sec_chan,
116 uint32 neg_flags, DOM_CHAL *srv_chal)
122 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
124 prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
125 prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
127 /* create and send a MSRPC command with api NET_AUTH2 */
129 DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
130 cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
131 credstr(cli->clnt_cred.challenge.data), neg_flags));
133 /* store the parameters */
134 init_q_auth_2(&q_a, cli->srv_name_slash, cli->mach_acct,
135 sec_chan, global_myname, &cli->clnt_cred.challenge, neg_flags);
137 /* turn parameters into data stream */
138 if(!net_io_q_auth_2("", &q_a, &buf, 0)) {
139 DEBUG(0,("cli_net_auth2: Error : failed to marshall NET_Q_AUTH_2 struct.\n"));
145 /* send the data on \PIPE\ */
146 if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
150 ok = net_io_r_auth_2("", &r_a, &rbuf, 0);
153 if (ok && !NT_STATUS_IS_OK(result))
155 /* report error code */
156 DEBUG(0,("cli_net_auth2: Error %s\n", nt_errstr(result)));
163 * Check the returned value using the initial
164 * server received challenge.
169 if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
171 * Server replied with bad credential. Fail.
173 DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
174 password ?).\n", cli->desthost ));
181 * Try commenting this out to see if this makes the connect
182 * work for a NT 3.51 PDC. JRA.
185 if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
187 /* report different neg_flags */
188 DEBUG(0,("cli_net_auth2: error neg_flags (q,r) differ - (%x,%x)\n",
189 q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
202 /****************************************************************************
203 LSA Request Challenge. Sends our challenge to server, then gets
204 server response. These are used to generate the credentials.
205 ****************************************************************************/
207 BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
212 BOOL valid_chal = False;
214 prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
215 prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
217 /* create and send a MSRPC command with api NET_REQCHAL */
219 DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
220 cli->desthost, global_myname, credstr(clnt_chal->data)));
222 /* store the parameters */
223 init_q_req_chal(&q_c, cli->srv_name_slash,
224 global_myname, clnt_chal);
226 /* turn parameters into data stream */
227 if(!net_io_q_req_chal("", &q_c, &buf, 0)) {
228 DEBUG(0,("cli_net_req_chal: Error : failed to marshall NET_Q_REQ_CHAL struct.\n"));
234 /* send the data on \PIPE\ */
235 if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
240 ok = net_io_r_req_chal("", &r_c, &rbuf, 0);
242 if (ok && !NT_STATUS_IS_OK(r_c.status))
244 /* report error code */
245 DEBUG(0,("cli_net_req_chal: Error %s\n", nt_errstr(r_c.status)));
251 /* ok, at last: we're happy. return the challenge */
252 memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
262 /***************************************************************************
263 LSA SAM Logon internal - interactive or network. Does level 2 or 3 but always
265 ****************************************************************************/
267 static NTSTATUS cli_net_sam_logon_internal(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
268 NET_USER_INFO_3 *user_info3,
269 uint16 validation_level)
271 DOM_CRED new_clnt_cred;
272 DOM_CRED dummy_rtn_creds;
277 NTSTATUS retval = NT_STATUS_OK;
279 gen_next_creds( cli, &new_clnt_cred);
281 prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
282 prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
284 /* create and send a MSRPC command with api NET_SAMLOGON */
286 DEBUG(4,("cli_net_sam_logon_internal: srv:%s mc:%s clnt %s %x ll: %d\n",
287 cli->srv_name_slash, global_myname,
288 credstr(new_clnt_cred.challenge.data), cli->clnt_cred.timestamp.time,
291 memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
292 dummy_rtn_creds.timestamp.time = time(NULL);
294 /* store the parameters */
295 q_s.validation_level = validation_level;
296 init_sam_info(&q_s.sam_id, cli->srv_name_slash,
297 global_myname, &new_clnt_cred, &dummy_rtn_creds,
298 ctr->switch_value, ctr);
300 /* turn parameters into data stream */
301 if(!net_io_q_sam_logon("", &q_s, &buf, 0)) {
302 DEBUG(0,("cli_net_sam_logon_internal: Error : failed to marshall NET_Q_SAM_LOGON struct.\n"));
303 retval = NT_STATUS_NO_MEMORY;
307 /* send the data on \PIPE\ */
308 if (!rpc_api_pipe_req(cli, NET_SAMLOGON, &buf, &rbuf)) {
309 DEBUG(0,("cli_net_sam_logon_internal: Error rpc_api_pipe_req failed.\n"));
310 retval = NT_STATUS_UNSUCCESSFUL;
314 r_s.user = user_info3;
316 if(!net_io_r_sam_logon("", &r_s, &rbuf, 0)) {
317 DEBUG(0,("cli_net_sam_logon_internal: Error : failed to unmarshal NET_R_SAM_LOGON struct.\n"));
318 retval = NT_STATUS_NO_MEMORY;
325 * Don't treat NT_STATUS_INVALID_INFO_CLASS as an error - we will re-issue
329 if (NT_STATUS_V(retval) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
333 if (!NT_STATUS_IS_OK(retval)) {
334 /* report error code */
335 DEBUG(0,("cli_net_sam_logon_internal: %s\n", nt_errstr(r_s.status)));
339 /* Update the credentials. */
340 if (!clnt_deal_with_creds(cli->sess_key, &cli->clnt_cred, &r_s.srv_creds)) {
342 * Server replied with bad credential. Fail.
344 DEBUG(0,("cli_net_sam_logon_internal: server %s replied with bad credential (bad machine \
345 password ?).\n", cli->desthost ));
346 retval = NT_STATUS_WRONG_PASSWORD;
349 if (r_s.switch_value != validation_level) {
350 /* report different switch_value */
351 DEBUG(0,("cli_net_sam_logon: switch_value of %x expected %x\n", (unsigned int)validation_level,
352 (unsigned int)r_s.switch_value));
353 retval = NT_STATUS_INVALID_PARAMETER;
364 /***************************************************************************
365 LSA SAM Logon - interactive or network.
366 ****************************************************************************/
368 NTSTATUS cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr,
369 NET_USER_INFO_3 *user_info3)
371 uint16 validation_level=3;
374 result = cli_net_sam_logon_internal(cli, ctr, user_info3,
377 if (NT_STATUS_IS_OK(result)) {
378 DEBUG(10,("cli_net_sam_logon: Success \n"));
379 } else if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
380 DEBUG(10,("cli_net_sam_logon: STATUS INVALID INFO CLASS \n"));
385 * Since this is the second time we call this function, don't care
386 * for the error. If its error, return False.
389 result = cli_net_sam_logon_internal(cli, ctr, user_info3,
396 /***************************************************************************
399 This currently doesnt work correctly as the domain controller
400 returns NT_STATUS_INVALID_INFO_CLASS - we obviously need to
401 send a different info level. Right now though, I'm not sure
402 what that needs to be (I need to see one on the wire before
404 ****************************************************************************/
405 BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
407 DOM_CRED new_clnt_cred;
408 DOM_CRED dummy_rtn_creds;
411 NET_Q_SAM_LOGOFF q_s;
414 gen_next_creds( cli, &new_clnt_cred);
416 prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
417 prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
419 /* create and send a MSRPC command with api NET_SAMLOGOFF */
421 DEBUG(4,("cli_net_sam_logoff: srv:%s mc:%s clnt %s %x ll: %d\n",
422 cli->srv_name_slash, global_myname,
423 credstr(new_clnt_cred.challenge.data), new_clnt_cred.timestamp.time,
426 memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
428 init_sam_info(&q_s.sam_id, cli->srv_name_slash,
429 global_myname, &new_clnt_cred, &dummy_rtn_creds,
430 ctr->switch_value, ctr);
432 /* turn parameters into data stream */
433 if(!net_io_q_sam_logoff("", &q_s, &buf, 0)) {
434 DEBUG(0,("cli_net_sam_logoff: Error : failed to marshall NET_Q_SAM_LOGOFF struct.\n"));
440 /* send the data on \PIPE\ */
441 if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
443 NET_R_SAM_LOGOFF r_s;
445 ok = net_io_r_sam_logoff("", &r_s, &rbuf, 0);
447 if (ok && !NT_STATUS_IS_OK(r_s.status))
449 /* report error code */
450 DEBUG(0,("cli_net_sam_logoff: %s\n", nt_errstr(r_s.status)));
454 /* Update the credentials. */
455 if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
458 * Server replied with bad credential. Fail.
460 DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
461 password ?).\n", cli->desthost ));