This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[jra/samba/.git] / source3 / rpc_client / cli_netlogon.c
1 /* 
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.
8  *
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.
13  *  
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.
18  *  
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.
22  */
23
24
25 #include "includes.h"
26
27 extern pstring global_myname;
28 extern fstring global_myworkgroup;
29
30 /****************************************************************************
31 Generate the next creds to use.
32 ****************************************************************************/
33
34 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
35 {
36   /*
37    * Create the new client credentials.
38    */
39
40   cli->clnt_cred.timestamp.time = time(NULL);
41
42   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
43
44   /* Calculate the new credentials. */
45   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
46               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
47
48 }
49
50 #if UNUSED_CODE
51 /****************************************************************************
52 do a LSA Logon Control2
53 ****************************************************************************/
54 BOOL cli_net_logon_ctrl2(struct cli_state *cli, NTSTATUS status_level)
55 {
56   prs_struct rbuf;
57   prs_struct buf; 
58   NET_Q_LOGON_CTRL2 q_l;
59   BOOL ok = False;
60
61   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
62   prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
63
64   /* create and send a MSRPC command with api NET_LOGON_CTRL2 */
65
66   DEBUG(4,("do_net_logon_ctrl2 from %s status level:%x\n",
67            global_myname, status_level));
68
69   /* store the parameters */
70   init_q_logon_ctrl2(&q_l, cli->srv_name_slash, 
71                      status_level);
72
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"));
76     prs_mem_free(&buf);
77     prs_mem_free(&rbuf);
78     return False;
79   }
80
81   /* send the data on \PIPE\ */
82   if (rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &buf, &rbuf))
83   {
84     NET_R_LOGON_CTRL2 r_l;
85
86     /*
87      * Unmarshall the return buffer.
88      */
89     ok = net_io_r_logon_ctrl2("", &r_l, &rbuf, 0);
90                 
91     if (ok && r_l.status != 0)
92     {
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;
96       ok = False;
97     }
98   }
99
100   prs_mem_free(&buf);
101   prs_mem_free(&rbuf);
102
103   return ok;
104 }
105 #endif
106
107 /****************************************************************************
108 LSA Authenticate 2
109
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 ****************************************************************************/
114
115 NTSTATUS cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
116                        uint32 neg_flags, DOM_CHAL *srv_chal)
117 {
118   prs_struct rbuf;
119   prs_struct buf; 
120   NET_Q_AUTH_2 q_a;
121   BOOL ok = False;
122   NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
123
124   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
125   prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
126
127   /* create and send a MSRPC command with api NET_AUTH2 */
128
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));
132
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);
136
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"));
140     prs_mem_free(&buf);
141     prs_mem_free(&rbuf);
142     return result;
143   }
144
145   /* send the data on \PIPE\ */
146   if (rpc_api_pipe_req(cli, NET_AUTH2, &buf, &rbuf))
147   {
148     NET_R_AUTH_2 r_a;
149
150     ok = net_io_r_auth_2("", &r_a, &rbuf, 0);
151     result = r_a.status;
152
153     if (ok && !NT_STATUS_IS_OK(result))
154     {
155       /* report error code */
156       DEBUG(0,("cli_net_auth2: Error %s\n", nt_errstr(result)));
157       ok = False;
158     }
159
160     if (ok)
161     {
162       /* 
163        * Check the returned value using the initial
164        * server received challenge.
165        */
166       UTIME zerotime;
167
168       zerotime.time = 0;
169       if(cred_assert( &r_a.srv_chal, cli->sess_key, srv_chal, zerotime) == 0) {
170         /*
171          * Server replied with bad credential. Fail.
172          */
173         DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
174 password ?).\n", cli->desthost ));
175         ok = False;
176       }
177     }
178
179 #if 0
180     /*
181      * Try commenting this out to see if this makes the connect
182      * work for a NT 3.51 PDC. JRA.
183      */
184
185     if (ok && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
186     {
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));
190       ok = False;
191     }
192 #endif
193
194   }
195
196   prs_mem_free(&buf);
197   prs_mem_free(&rbuf);
198
199   return result;
200 }
201
202 /****************************************************************************
203 LSA Request Challenge. Sends our challenge to server, then gets
204 server response. These are used to generate the credentials.
205 ****************************************************************************/
206
207 BOOL cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
208 {
209   prs_struct rbuf;
210   prs_struct buf; 
211   NET_Q_REQ_CHAL q_c;
212   BOOL valid_chal = False;
213
214   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
215   prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
216
217   /* create and send a MSRPC command with api NET_REQCHAL */
218
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)));
221
222   /* store the parameters */
223   init_q_req_chal(&q_c, cli->srv_name_slash, 
224                   global_myname, clnt_chal);
225
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"));
229     prs_mem_free(&buf);
230     prs_mem_free(&rbuf);
231     return False;
232   }
233
234   /* send the data on \PIPE\ */
235   if (rpc_api_pipe_req(cli, NET_REQCHAL, &buf, &rbuf))
236   {
237     NET_R_REQ_CHAL r_c;
238     BOOL ok;
239
240     ok = net_io_r_req_chal("", &r_c, &rbuf, 0);
241                 
242     if (ok && !NT_STATUS_IS_OK(r_c.status))
243     {
244       /* report error code */
245       DEBUG(0,("cli_net_req_chal: Error %s\n", nt_errstr(r_c.status)));
246       ok = False;
247     }
248
249     if (ok)
250     {
251       /* ok, at last: we're happy. return the challenge */
252       memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
253       valid_chal = True;
254     }
255   }
256
257   prs_mem_free(&buf);
258   prs_mem_free(&rbuf);
259
260   return valid_chal;
261 }
262 /***************************************************************************
263  LSA SAM Logon internal - interactive or network. Does level 2 or 3 but always
264  returns level 3.
265 ****************************************************************************/
266
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)
270 {
271         DOM_CRED new_clnt_cred;
272         DOM_CRED dummy_rtn_creds;
273         prs_struct rbuf;
274         prs_struct buf; 
275         NET_Q_SAM_LOGON q_s;
276         NET_R_SAM_LOGON r_s;
277         NTSTATUS retval = NT_STATUS_OK;
278
279         gen_next_creds( cli, &new_clnt_cred);
280
281         prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
282         prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
283
284         /* create and send a MSRPC command with api NET_SAMLOGON */
285
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,
289              ctr->switch_value));
290
291         memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
292         dummy_rtn_creds.timestamp.time = time(NULL);
293
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);
299
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;
304                 goto out;
305         }
306
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;
311                 goto out;
312         }
313
314         r_s.user = user_info3;
315
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;
319                 goto out;
320         }
321                 
322         retval = r_s.status;
323
324         /*
325          * Don't treat NT_STATUS_INVALID_INFO_CLASS as an error - we will re-issue
326          * the call.
327          */
328         
329         if (NT_STATUS_V(retval) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
330                 goto out;
331         }
332
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)));
336                 goto out;
337         }
338
339         /* Update the credentials. */
340         if (!clnt_deal_with_creds(cli->sess_key, &cli->clnt_cred, &r_s.srv_creds)) {
341                 /*
342                  * Server replied with bad credential. Fail.
343                  */
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;
347         }
348         
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;
354         }
355
356 out:
357
358         prs_mem_free(&buf);
359         prs_mem_free(&rbuf);
360         
361         return retval;
362 }
363
364 /***************************************************************************
365 LSA SAM Logon - interactive or network.
366 ****************************************************************************/
367
368 NTSTATUS cli_net_sam_logon(struct cli_state *cli, NET_ID_INFO_CTR *ctr, 
369                          NET_USER_INFO_3 *user_info3)
370 {
371         uint16 validation_level=3;
372         NTSTATUS result;
373
374         result = cli_net_sam_logon_internal(cli, ctr, user_info3, 
375                                             validation_level);
376
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"));
381
382                 validation_level=2;
383
384                 /*
385                  * Since this is the second time we call this function, don't care
386                  * for the error. If its error, return False. 
387                  */
388
389                 result = cli_net_sam_logon_internal(cli, ctr, user_info3,
390                                                     validation_level);
391         }
392
393         return result;
394 }
395
396 /***************************************************************************
397 LSA SAM Logoff.
398
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
403 I can be sure). JRA.
404 ****************************************************************************/
405 BOOL cli_net_sam_logoff(struct cli_state *cli, NET_ID_INFO_CTR *ctr)
406 {
407   DOM_CRED new_clnt_cred;
408   DOM_CRED dummy_rtn_creds;
409   prs_struct rbuf;
410   prs_struct buf; 
411   NET_Q_SAM_LOGOFF q_s;
412   BOOL ok = False;
413
414   gen_next_creds( cli, &new_clnt_cred);
415
416   prs_init(&buf , 1024, cli->mem_ctx, MARSHALL);
417   prs_init(&rbuf, 0,    cli->mem_ctx, UNMARSHALL);
418
419   /* create and send a MSRPC command with api NET_SAMLOGOFF */
420
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,
424             ctr->switch_value));
425
426   memset(&dummy_rtn_creds, '\0', sizeof(dummy_rtn_creds));
427
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);
431
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"));
435     prs_mem_free(&buf);
436     prs_mem_free(&rbuf);
437     return False;
438   }
439
440   /* send the data on \PIPE\ */
441   if (rpc_api_pipe_req(cli, NET_SAMLOGOFF, &buf, &rbuf))
442   {
443     NET_R_SAM_LOGOFF r_s;
444
445     ok = net_io_r_sam_logoff("", &r_s, &rbuf, 0);
446                 
447     if (ok && !NT_STATUS_IS_OK(r_s.status))
448     {
449       /* report error code */
450       DEBUG(0,("cli_net_sam_logoff: %s\n", nt_errstr(r_s.status)));
451       ok = False;
452     }
453
454     /* Update the credentials. */
455     if (ok && !clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), &(r_s.srv_creds)))
456     {
457       /*
458        * Server replied with bad credential. Fail.
459        */
460       DEBUG(0,("cli_net_sam_logoff: server %s replied with bad credential (bad machine \
461 password ?).\n", cli->desthost ));
462       ok = False;
463     }
464   }
465
466   prs_mem_free(&buf);
467   prs_mem_free(&rbuf);
468
469   return ok;
470 }