~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/utils/net_domain.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Samba Unix/Linux SMB client library 
3
 
   net ads commands
4
 
   Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5
 
   Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
6
 
   Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
7
 
   Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
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
 
#include "utils/net.h"
26
 
 
27
 
/* Macro for checking RPC error codes to make things more readable */
28
 
 
29
 
#define CHECK_RPC_ERR(rpc, msg) \
30
 
        if (!NT_STATUS_IS_OK(result = rpc)) { \
31
 
                DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
32
 
                goto done; \
33
 
        }
34
 
 
35
 
#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
36
 
        if (!NT_STATUS_IS_OK(result = rpc)) { \
37
 
                DEBUG(0, debug_args); \
38
 
                goto done; \
39
 
        }
40
 
 
41
 
/*******************************************************************
42
 
 Leave an AD domain.  Windows XP disables the machine account.
43
 
 We'll try the same.  The old code would do an LDAP delete.
44
 
 That only worked using the machine creds because added the machine
45
 
 with full control to the computer object's ACL.
46
 
*******************************************************************/
47
 
 
48
 
NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
49
 
                         DOM_SID *dom_sid )
50
 
{       
51
 
        struct rpc_pipe_client *pipe_hnd = NULL;
52
 
        POLICY_HND sam_pol, domain_pol, user_pol;
53
 
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
54
 
        char *acct_name;
55
 
        uint32 flags = 0x3e8;
56
 
        const char *const_acct_name;
57
 
        uint32 user_rid;
58
 
        uint32 num_rids, *name_types, *user_rids;
59
 
        SAM_USERINFO_CTR ctr, *qctr = NULL;
60
 
        SAM_USER_INFO_16 p16;
61
 
 
62
 
        /* Open the domain */
63
 
        
64
 
        if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
65
 
                DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
66
 
                        nt_errstr(status) ));
67
 
                return status;
68
 
        }
69
 
 
70
 
        status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
71
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
72
 
        if ( !NT_STATUS_IS_OK(status) )
73
 
                return status;
74
 
 
75
 
        
76
 
        status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
77
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
78
 
        if ( !NT_STATUS_IS_OK(status) )
79
 
                return status;
80
 
 
81
 
        /* Create domain user */
82
 
        
83
 
        acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
84
 
        strlower_m(acct_name);
85
 
        const_acct_name = acct_name;
86
 
 
87
 
        status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
88
 
                        &domain_pol, flags, 1, &const_acct_name, 
89
 
                        &num_rids, &user_rids, &name_types);
90
 
        if ( !NT_STATUS_IS_OK(status) )
91
 
                return status;
92
 
 
93
 
        if ( name_types[0] != SID_NAME_USER) {
94
 
                DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
95
 
                return NT_STATUS_INVALID_WORKSTATION;
96
 
        }
97
 
 
98
 
        user_rid = user_rids[0];
99
 
                
100
 
        /* Open handle on user */
101
 
 
102
 
        status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
103
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
104
 
        if ( !NT_STATUS_IS_OK(status) ) {
105
 
                goto done;
106
 
        }
107
 
        
108
 
        /* Get user info */
109
 
 
110
 
        status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
111
 
        if ( !NT_STATUS_IS_OK(status) ) {
112
 
                rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
113
 
                goto done;
114
 
        }
115
 
 
116
 
        /* now disable and setuser info */
117
 
        
118
 
        ZERO_STRUCT(ctr);
119
 
        ctr.switch_value = 16;
120
 
        ctr.info.id16 = &p16;
121
 
 
122
 
        p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
123
 
 
124
 
        status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
125
 
                                        &cli->user_session_key, &ctr);
126
 
 
127
 
        rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
128
 
 
129
 
done:
130
 
        rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
131
 
        rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
132
 
        
133
 
        cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
134
 
        
135
 
        return status;
136
 
}
137
 
 
138
 
/*******************************************************************
139
 
 Store the machine password and domain SID
140
 
 ********************************************************************/
141
 
 
142
 
int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
143
 
{
144
 
        if (!secrets_store_domain_sid(domain, sid)) {
145
 
                DEBUG(1,("Failed to save domain sid\n"));
146
 
                return -1;
147
 
        }
148
 
 
149
 
        if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
150
 
                DEBUG(1,("Failed to save machine password\n"));
151
 
                return -1;
152
 
        }
153
 
 
154
 
        return 0;
155
 
}
156
 
 
157
 
/*******************************************************************
158
 
 ********************************************************************/
159
 
 
160
 
NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
161
 
{
162
 
        struct rpc_pipe_client *pipe_hnd = NULL;
163
 
        POLICY_HND lsa_pol;
164
 
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
165
 
        char *domain = NULL;
166
 
 
167
 
        if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
168
 
                DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
169
 
                        nt_errstr(status) ));
170
 
                return status;
171
 
        }
172
 
 
173
 
        status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
174
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
175
 
        if ( !NT_STATUS_IS_OK(status) )
176
 
                return status;
177
 
 
178
 
        status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx, 
179
 
                        &lsa_pol, 5, &domain, sid);
180
 
        if ( !NT_STATUS_IS_OK(status) )
181
 
                return status;
182
 
 
183
 
        rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
184
 
        cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
185
 
 
186
 
        /* Bail out if domain didn't get set. */
187
 
        if (!domain) {
188
 
                DEBUG(0, ("Could not get domain name.\n"));
189
 
                return NT_STATUS_UNSUCCESSFUL;
190
 
        }
191
 
        
192
 
        return NT_STATUS_OK;
193
 
}
194
 
 
195
 
/*******************************************************************
196
 
 Do the domain join
197
 
 ********************************************************************/
198
 
 
199
 
NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, 
200
 
                           DOM_SID *dom_sid, const char *clear_pw,
201
 
                           enum netdom_domain_t dom_type )
202
 
{       
203
 
        struct rpc_pipe_client *pipe_hnd = NULL;
204
 
        POLICY_HND sam_pol, domain_pol, user_pol;
205
 
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206
 
        char *acct_name;
207
 
        const char *const_acct_name;
208
 
        uint32 user_rid;
209
 
        uint32 num_rids, *name_types, *user_rids;
210
 
        uint32 flags = 0x3e8;
211
 
        uint32 acb_info = ACB_WSTRUST;
212
 
        uchar pwbuf[516];
213
 
        SAM_USERINFO_CTR ctr;
214
 
        SAM_USER_INFO_24 p24;
215
 
        SAM_USER_INFO_16 p16;
216
 
        uchar md4_trust_password[16];
217
 
 
218
 
        /* Open the domain */
219
 
        
220
 
        if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
221
 
                DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
222
 
                        nt_errstr(status) ));
223
 
                return status;
224
 
        }
225
 
 
226
 
        status = rpccli_samr_connect(pipe_hnd, mem_ctx, 
227
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
228
 
        if ( !NT_STATUS_IS_OK(status) )
229
 
                return status;
230
 
 
231
 
        
232
 
        status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
233
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
234
 
        if ( !NT_STATUS_IS_OK(status) )
235
 
                return status;
236
 
 
237
 
        /* Create domain user */
238
 
        
239
 
        acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); 
240
 
        strlower_m(acct_name);
241
 
        const_acct_name = acct_name;
242
 
 
243
 
        /* Don't try to set any acb_info flags other than ACB_WSTRUST */
244
 
 
245
 
        status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
246
 
                        acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
247
 
 
248
 
        if ( !NT_STATUS_IS_OK(status) 
249
 
                && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) 
250
 
        {
251
 
                d_fprintf(stderr, "Creation of workstation account failed\n");
252
 
 
253
 
                /* If NT_STATUS_ACCESS_DENIED then we have a valid
254
 
                   username/password combo but the user does not have
255
 
                   administrator access. */
256
 
 
257
 
                if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
258
 
                        d_fprintf(stderr, "User specified does not have administrator privileges\n");
259
 
 
260
 
                return status;
261
 
        }
262
 
 
263
 
        /* We *must* do this.... don't ask... */
264
 
 
265
 
        if (NT_STATUS_IS_OK(status)) {
266
 
                rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
267
 
        }
268
 
 
269
 
        status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
270
 
                        &domain_pol, flags, 1, &const_acct_name, 
271
 
                        &num_rids, &user_rids, &name_types);
272
 
        if ( !NT_STATUS_IS_OK(status) )
273
 
                return status;
274
 
 
275
 
        if ( name_types[0] != SID_NAME_USER) {
276
 
                DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
277
 
                return NT_STATUS_INVALID_WORKSTATION;
278
 
        }
279
 
 
280
 
        user_rid = user_rids[0];
281
 
                
282
 
        /* Open handle on user */
283
 
 
284
 
        status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
285
 
                        SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
286
 
        
287
 
        /* Create a random machine account password */
288
 
 
289
 
        E_md4hash( clear_pw, md4_trust_password);
290
 
        encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
291
 
 
292
 
        /* Set password on machine account */
293
 
 
294
 
        ZERO_STRUCT(ctr);
295
 
        ZERO_STRUCT(p24);
296
 
 
297
 
        init_sam_user_info24(&p24, (char *)pwbuf,24);
298
 
 
299
 
        ctr.switch_value = 24;
300
 
        ctr.info.id24 = &p24;
301
 
 
302
 
        status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol, 
303
 
                        24, &cli->user_session_key, &ctr);
304
 
 
305
 
        if ( !NT_STATUS_IS_OK(status) ) {
306
 
                d_fprintf( stderr, "Failed to set password for machine account (%s)\n", 
307
 
                        nt_errstr(status));
308
 
                return status;
309
 
        }
310
 
 
311
 
 
312
 
        /* Why do we have to try to (re-)set the ACB to be the same as what
313
 
           we passed in the samr_create_dom_user() call?  When a NT
314
 
           workstation is joined to a domain by an administrator the
315
 
           acb_info is set to 0x80.  For a normal user with "Add
316
 
           workstations to the domain" rights the acb_info is 0x84.  I'm
317
 
           not sure whether it is supposed to make a difference or not.  NT
318
 
           seems to cope with either value so don't bomb out if the set
319
 
           userinfo2 level 0x10 fails.  -tpot */
320
 
 
321
 
        ZERO_STRUCT(ctr);
322
 
        ctr.switch_value = 16;
323
 
        ctr.info.id16 = &p16;
324
 
 
325
 
        /* Fill in the additional account flags now */
326
 
 
327
 
        acb_info |= ACB_PWNOEXP;
328
 
        if ( dom_type == ND_TYPE_AD ) {
329
 
#if !defined(ENCTYPE_ARCFOUR_HMAC)
330
 
                acb_info |= ACB_USE_DES_KEY_ONLY;
331
 
#endif
332
 
                ;;
333
 
        }
334
 
 
335
 
        init_sam_user_info16(&p16, acb_info);
336
 
 
337
 
        status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16, 
338
 
                                        &cli->user_session_key, &ctr);
339
 
 
340
 
        rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
341
 
        cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
342
 
        
343
 
        return status;
344
 
}
345