more warning fixes on solaris
[samba.git] / source / libsmb / cli_netlogon.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NT Domain Authentication SMB / MSRPC client
5    Copyright (C) Andrew Tridgell 1994-2000
6    Copyright (C) Luke Kenneth Casson Leighton 1996-2000
7    Copyright (C) Tim Potter 2001
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 #include "includes.h"
25
26 /* Opens a SMB connection to the netlogon pipe */
27
28 struct cli_state *cli_netlogon_initialise(struct cli_state *cli, 
29                                           char *system_name,
30                                           struct ntuser_creds *creds)
31 {
32         return cli_pipe_initialise(cli, system_name, PIPE_NETLOGON, creds);
33 }
34
35 /* LSA Request Challenge. Sends our challenge to server, then gets
36    server response. These are used to generate the credentials. */
37
38 NTSTATUS new_cli_net_req_chal(struct cli_state *cli, DOM_CHAL *clnt_chal, 
39                               DOM_CHAL *srv_chal)
40 {
41         prs_struct qbuf, rbuf;
42         NET_Q_REQ_CHAL q;
43         NET_R_REQ_CHAL r;
44         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
45         extern pstring global_myname;
46
47         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
48         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
49         
50         /* create and send a MSRPC command with api NET_REQCHAL */
51
52         DEBUG(4,("cli_net_req_chal: LSA Request Challenge from %s to %s: %s\n",
53                  cli->desthost, global_myname, credstr(clnt_chal->data)));
54         
55         /* store the parameters */
56         init_q_req_chal(&q, cli->srv_name_slash, global_myname, clnt_chal);
57         
58         /* Marshall data and send request */
59
60         if (!net_io_q_req_chal("", &q,  &qbuf, 0) ||
61             !rpc_api_pipe_req(cli, NET_REQCHAL, &qbuf, &rbuf)) {
62                 goto done;
63         }
64
65         /* Unmarhall response */
66
67         if (!net_io_r_req_chal("", &r, &rbuf, 0)) {
68                 goto done;
69         }
70
71         result = r.status;
72
73         /* Return result */
74
75         if (result == NT_STATUS_OK) {
76                 memcpy(srv_chal, r.srv_chal.data, sizeof(srv_chal->data));
77         }
78         
79  done:
80         prs_mem_free(&qbuf);
81         prs_mem_free(&rbuf);
82         
83         return result;
84 }
85
86 /****************************************************************************
87 LSA Authenticate 2
88
89 Send the client credential, receive back a server credential.
90 Ensure that the server credential returned matches the session key 
91 encrypt of the server challenge originally received. JRA.
92 ****************************************************************************/
93
94 NTSTATUS new_cli_net_auth2(struct cli_state *cli, uint16 sec_chan, 
95                            uint32 neg_flags, DOM_CHAL *srv_chal)
96 {
97         prs_struct qbuf, rbuf;
98         NET_Q_AUTH_2 q;
99         NET_R_AUTH_2 r;
100         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
101         extern pstring global_myname;
102
103         prs_init(&qbuf, MAX_PDU_FRAG_LEN, cli->mem_ctx, MARSHALL);
104         prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL);
105
106         /* create and send a MSRPC command with api NET_AUTH2 */
107
108         DEBUG(4,("cli_net_auth2: srv:%s acct:%s sc:%x mc: %s chal %s neg: %x\n",
109                  cli->srv_name_slash, cli->mach_acct, sec_chan, global_myname,
110                  credstr(cli->clnt_cred.challenge.data), neg_flags));
111
112         /* store the parameters */
113         init_q_auth_2(&q, cli->srv_name_slash, cli->mach_acct, 
114                       sec_chan, global_myname, &cli->clnt_cred.challenge, 
115                       neg_flags);
116
117         /* turn parameters into data stream */
118
119         if (!net_io_q_auth_2("", &q,  &qbuf, 0) ||
120             !rpc_api_pipe_req(cli, NET_AUTH2, &qbuf, &rbuf)) {
121                 goto done;
122         }
123         
124         /* Unmarshall response */
125         
126         if (!net_io_r_auth_2("", &r, &rbuf, 0)) {
127                 goto done;
128         }
129
130         result = r.status;
131
132         if (result == NT_STATUS_OK) {
133                 UTIME zerotime;
134                 
135                 /*
136                  * Check the returned value using the initial
137                  * server received challenge.
138                  */
139
140                 zerotime.time = 0;
141                 if (cred_assert( &r.srv_chal, cli->sess_key, srv_chal, 
142                                  zerotime) == 0) {
143
144                         /*
145                          * Server replied with bad credential. Fail.
146                          */
147                         DEBUG(0,("cli_net_auth2: server %s replied with bad credential (bad machine \
148 password ?).\n", cli->desthost ));
149                         result = NT_STATUS_ACCESS_DENIED;
150                         goto done;
151                 }
152         }
153
154  done:
155         prs_mem_free(&qbuf);
156         prs_mem_free(&rbuf);
157         
158         return result;
159 }
160
161 /* Initialize domain session credentials */
162
163 NTSTATUS new_cli_nt_setup_creds(struct cli_state *cli, 
164                                 unsigned char mach_pwd[16])
165 {
166         DOM_CHAL clnt_chal;
167         DOM_CHAL srv_chal;
168         UTIME zerotime;
169         NTSTATUS result;
170
171         /******************* Request Challenge ********************/
172
173         generate_random_buffer(clnt_chal.data, 8, False);
174         
175         /* send a client challenge; receive a server challenge */
176         result = new_cli_net_req_chal(cli, &clnt_chal, &srv_chal);
177
178         if (result != NT_STATUS_OK) {
179                 DEBUG(0,("cli_nt_setup_creds: request challenge failed\n"));
180                 return result;
181         }
182         
183         /**************** Long-term Session key **************/
184
185         /* calculate the session key */
186         cred_session_key(&clnt_chal, &srv_chal, (char *)mach_pwd, 
187                          cli->sess_key);
188         memset((char *)cli->sess_key+8, '\0', 8);
189
190         /******************* Authenticate 2 ********************/
191
192         /* calculate auth-2 credentials */
193         zerotime.time = 0;
194         cred_create(cli->sess_key, &clnt_chal, zerotime, 
195                     &cli->clnt_cred.challenge);
196
197         /*  
198          * Send client auth-2 challenge.
199          * Receive an auth-2 challenge response and check it.
200          */
201         
202         if (!new_cli_net_auth2(cli, (lp_server_role() == ROLE_DOMAIN_MEMBER) ?
203                                SEC_CHAN_WKSTA : SEC_CHAN_BDC, 0x000001ff, 
204                                &srv_chal)) {
205                 DEBUG(0,("cli_nt_setup_creds: auth2 challenge failed\n"));
206                 return False;
207         }
208
209         return True;
210 }
211
212 /* Logon Control 2 */
213
214 NTSTATUS cli_netlogon_logon_ctrl2(struct cli_state *cli, TALLOC_CTX *mem_ctx,
215                                   uint32 query_level)
216 {
217         prs_struct qbuf, rbuf;
218         NET_Q_LOGON_CTRL2 q;
219         NET_R_LOGON_CTRL2 r;
220         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
221
222         ZERO_STRUCT(q);
223         ZERO_STRUCT(r);
224
225         /* Initialise parse structures */
226
227         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
228         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
229
230         /* Initialise input parameters */
231
232         init_net_q_logon_ctrl2(&q, cli->srv_name_slash, query_level);
233
234         /* Marshall data and send request */
235
236         if (!net_io_q_logon_ctrl2("", &q, &qbuf, 0) ||
237             !rpc_api_pipe_req(cli, NET_LOGON_CTRL2, &qbuf, &rbuf)) {
238                 result = NT_STATUS_UNSUCCESSFUL;
239                 goto done;
240         }
241
242         /* Unmarshall response */
243
244         if (!net_io_r_logon_ctrl2("", &r, &rbuf, 0)) {
245                 result = NT_STATUS_UNSUCCESSFUL;
246                 goto done;
247         }
248
249         result = r.status;
250
251  done:
252         prs_mem_free(&qbuf);
253         prs_mem_free(&rbuf);
254
255         return result;
256 }
257
258 /****************************************************************************
259 Generate the next creds to use.  Yuck - this is a cut&paste from another
260 file.  They should be combined at some stage.  )-:
261 ****************************************************************************/
262
263 static void gen_next_creds( struct cli_state *cli, DOM_CRED *new_clnt_cred)
264 {
265   /*
266    * Create the new client credentials.
267    */
268
269   cli->clnt_cred.timestamp.time = time(NULL);
270
271   memcpy(new_clnt_cred, &cli->clnt_cred, sizeof(*new_clnt_cred));
272
273   /* Calculate the new credentials. */
274   cred_create(cli->sess_key, &(cli->clnt_cred.challenge),
275               new_clnt_cred->timestamp, &(new_clnt_cred->challenge));
276
277 }
278
279 /* Sam synchronisation */
280
281 NTSTATUS cli_netlogon_sam_sync(struct cli_state *cli, TALLOC_CTX *mem_ctx,
282                                uint32 database_id, uint32 *num_deltas,
283                                SAM_DELTA_HDR **hdr_deltas, 
284                                SAM_DELTA_CTR **deltas)
285 {
286         prs_struct qbuf, rbuf;
287         NET_Q_SAM_SYNC q;
288         NET_R_SAM_SYNC r;
289         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
290         DOM_CRED clnt_creds;
291         uchar sess_key[16];
292
293         ZERO_STRUCT(q);
294         ZERO_STRUCT(r);
295
296         /* Initialise parse structures */
297
298         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
299         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
300
301         /* Initialise input parameters */
302
303         gen_next_creds(cli, &clnt_creds);
304
305         init_net_q_sam_sync(&q, cli->srv_name_slash, cli->clnt_name_slash + 2,
306                             &clnt_creds, database_id);
307
308         /* Marshall data and send request */
309
310         if (!net_io_q_sam_sync("", &q, &qbuf, 0) ||
311             !rpc_api_pipe_req(cli, NET_SAM_SYNC, &qbuf, &rbuf)) {
312                 result = NT_STATUS_UNSUCCESSFUL;
313                 goto done;
314         }
315
316         /* Unmarshall response */
317
318         if (!net_io_r_sam_sync("", sess_key, &r, &rbuf, 0)) {
319                 result = NT_STATUS_UNSUCCESSFUL;
320                 goto done;
321         }
322
323         /* Return results */
324
325         result = r.status;
326         *num_deltas = r.num_deltas2;
327         *hdr_deltas = r.hdr_deltas;
328         *deltas = r.deltas;
329
330  done:
331         prs_mem_free(&qbuf);
332         prs_mem_free(&rbuf);
333
334         return result;
335 }
336
337 /* Sam synchronisation */
338
339 NTSTATUS cli_netlogon_sam_deltas(struct cli_state *cli, TALLOC_CTX *mem_ctx,
340                                  uint32 database_id, UINT64_S seqnum,
341                                  uint32 *num_deltas, 
342                                  SAM_DELTA_HDR **hdr_deltas, 
343                                  SAM_DELTA_CTR **deltas)
344 {
345         prs_struct qbuf, rbuf;
346         NET_Q_SAM_DELTAS q;
347         NET_R_SAM_DELTAS r;
348         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
349         DOM_CRED clnt_creds;
350         uchar sess_key[16];
351
352         ZERO_STRUCT(q);
353         ZERO_STRUCT(r);
354
355         /* Initialise parse structures */
356
357         prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
358         prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
359
360         /* Initialise input parameters */
361
362         gen_next_creds(cli, &clnt_creds);
363
364         init_net_q_sam_deltas(&q, cli->srv_name_slash, 
365                               cli->clnt_name_slash + 2, &clnt_creds, 
366                               database_id, seqnum);
367
368         /* Marshall data and send request */
369
370         if (!net_io_q_sam_deltas("", &q, &qbuf, 0) ||
371             !rpc_api_pipe_req(cli, NET_SAM_DELTAS, &qbuf, &rbuf)) {
372                 result = NT_STATUS_UNSUCCESSFUL;
373                 goto done;
374         }
375
376         /* Unmarshall response */
377
378         if (!net_io_r_sam_deltas("", sess_key, &r, &rbuf, 0)) {
379                 result = NT_STATUS_UNSUCCESSFUL;
380                 goto done;
381         }
382
383         /* Return results */
384
385         result = r.status;
386         *num_deltas = r.num_deltas2;
387         *hdr_deltas = r.hdr_deltas;
388         *deltas = r.deltas;
389
390  done:
391         prs_mem_free(&qbuf);
392         prs_mem_free(&rbuf);
393
394         return result;
395 }