49e65066e5f34bbd6912eae7aad0928bb2a21d8e
[samba.git] / source3 / rpc_server / dfs / srv_dfs_nt.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines for Dfs
4  *  Copyright (C) Shirish Kalele        2000.
5  *  Copyright (C) Jeremy Allison        2001-2007.
6  *  Copyright (C) Jelmer Vernooij       2005-2006.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /* This is the implementation of the dfs pipe. */
23
24 #include "includes.h"
25 #include "ntdomain.h"
26 #include "../librpc/gen_ndr/srv_dfs.h"
27 #include "msdfs.h"
28 #include "smbd/smbd.h"
29 #include "smbd/globals.h"
30 #include "auth.h"
31
32 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_MSDFS
34
35 /* This function does not return a WERROR or NTSTATUS code but rather 1 if
36    dfs exists, or 0 otherwise. */
37
38 void _dfs_GetManagerVersion(struct pipes_struct *p, struct dfs_GetManagerVersion *r)
39 {
40         if (lp_host_msdfs()) {
41                 *r->out.version = DFS_MANAGER_VERSION_NT4;
42         } else {
43                 *r->out.version = (enum dfs_ManagerVersion)0;
44         }
45 }
46
47 WERROR _dfs_Add(struct pipes_struct *p, struct dfs_Add *r)
48 {
49         struct junction_map *jn = NULL;
50         struct referral *old_referral_list = NULL;
51         bool self_ref = False;
52         int consumedcnt = 0;
53         char *altpath = NULL;
54         NTSTATUS status;
55         TALLOC_CTX *ctx = talloc_tos();
56
57         if (p->session_info->unix_token->uid != sec_initial_uid()) {
58                 DEBUG(10,("_dfs_add: uid != 0. Access denied.\n"));
59                 return WERR_ACCESS_DENIED;
60         }
61
62         jn = talloc_zero(ctx, struct junction_map);
63         if (!jn) {
64                 return WERR_NOMEM;
65         }
66
67         DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
68                 r->in.path, r->in.server, r->in.share));
69
70         altpath = talloc_asprintf(ctx, "%s\\%s",
71                         r->in.server,
72                         r->in.share);
73         if (!altpath) {
74                 return WERR_NOMEM;
75         }
76
77         /* The following call can change the cwd. */
78         status = get_referred_path(ctx, r->in.path,
79                                    true, /*allow_broken_path */
80                                    jn, &consumedcnt, &self_ref);
81         if(!NT_STATUS_IS_OK(status)) {
82                 return ntstatus_to_werror(status);
83         }
84
85         jn->referral_count += 1;
86         old_referral_list = jn->referral_list;
87
88         if (jn->referral_count < 1) {
89                 return WERR_NOMEM;
90         }
91
92         jn->referral_list = talloc_array(ctx, struct referral, jn->referral_count);
93         if(jn->referral_list == NULL) {
94                 DEBUG(0,("init_reply_dfs_add: talloc failed for referral list!\n"));
95                 return WERR_DFS_INTERNAL_ERROR;
96         }
97
98         if(old_referral_list && jn->referral_list) {
99                 memcpy(jn->referral_list, old_referral_list,
100                                 sizeof(struct referral)*jn->referral_count-1);
101         }
102
103         jn->referral_list[jn->referral_count-1].proximity = 0;
104         jn->referral_list[jn->referral_count-1].ttl = REFERRAL_TTL;
105         jn->referral_list[jn->referral_count-1].alternate_path = altpath;
106
107         if(!create_msdfs_link(jn)) {
108                 return WERR_DFS_CANT_CREATE_JUNCT;
109         }
110
111         return WERR_OK;
112 }
113
114 WERROR _dfs_Remove(struct pipes_struct *p, struct dfs_Remove *r)
115 {
116         struct junction_map *jn = NULL;
117         bool self_ref = False;
118         int consumedcnt = 0;
119         bool found = False;
120         TALLOC_CTX *ctx = talloc_tos();
121         char *altpath = NULL;
122         NTSTATUS status;
123
124         if (p->session_info->unix_token->uid != sec_initial_uid()) {
125                 DEBUG(10,("_dfs_remove: uid != 0. Access denied.\n"));
126                 return WERR_ACCESS_DENIED;
127         }
128
129         jn = talloc_zero(ctx, struct junction_map);
130         if (!jn) {
131                 return WERR_NOMEM;
132         }
133
134         if (r->in.servername && r->in.sharename) {
135                 altpath = talloc_asprintf(ctx, "%s\\%s",
136                         r->in.servername,
137                         r->in.sharename);
138                 if (!altpath) {
139                         return WERR_NOMEM;
140                 }
141                 strlower_m(altpath);
142                 DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
143                         r->in.dfs_entry_path, r->in.servername, r->in.sharename));
144         }
145
146         status = get_referred_path(ctx, r->in.dfs_entry_path,
147                                    true, /*allow_broken_path */
148                                    jn, &consumedcnt, &self_ref);
149         if(!NT_STATUS_IS_OK(status)) {
150                 return WERR_DFS_NO_SUCH_VOL;
151         }
152
153         /* if no server-share pair given, remove the msdfs link completely */
154         if(!r->in.servername && !r->in.sharename) {
155                 if(!remove_msdfs_link(jn)) {
156                         return WERR_DFS_NO_SUCH_VOL;
157                 }
158         } else {
159                 int i=0;
160                 /* compare each referral in the list with the one to remove */
161                 DEBUG(10,("altpath: .%s. refcnt: %d\n", altpath, jn->referral_count));
162                 for(i=0;i<jn->referral_count;i++) {
163                         char *refpath = talloc_strdup(ctx,
164                                         jn->referral_list[i].alternate_path);
165                         if (!refpath) {
166                                 return WERR_NOMEM;
167                         }
168                         trim_char(refpath, '\\', '\\');
169                         DEBUG(10,("_dfs_remove:  refpath: .%s.\n", refpath));
170                         if(strequal(refpath, altpath)) {
171                                 *(jn->referral_list[i].alternate_path)='\0';
172                                 DEBUG(10,("_dfs_remove: Removal request matches referral %s\n",
173                                         refpath));
174                                 found = True;
175                         }
176                 }
177
178                 if(!found) {
179                         return WERR_DFS_NO_SUCH_SHARE;
180                 }
181
182                 /* Only one referral, remove it */
183                 if(jn->referral_count == 1) {
184                         if(!remove_msdfs_link(jn)) {
185                                 return WERR_DFS_NO_SUCH_VOL;
186                         }
187                 } else {
188                         if(!create_msdfs_link(jn)) {
189                                 return WERR_DFS_CANT_CREATE_JUNCT;
190                         }
191                 }
192         }
193
194         return WERR_OK;
195 }
196
197 static bool init_reply_dfs_info_1(TALLOC_CTX *mem_ctx, struct junction_map* j,struct dfs_Info1* dfs1)
198 {
199         dfs1->path = talloc_asprintf(mem_ctx,
200                                 "\\\\%s\\%s\\%s", lp_netbios_name(),
201                                 j->service_name, j->volume_name);
202         if (dfs1->path == NULL)
203                 return False;
204
205         DEBUG(5,("init_reply_dfs_info_1: initing entrypath: %s\n",dfs1->path));
206         return True;
207 }
208
209 static bool init_reply_dfs_info_2(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info2* dfs2)
210 {
211         dfs2->path = talloc_asprintf(mem_ctx,
212                         "\\\\%s\\%s\\%s", lp_netbios_name(), j->service_name, j->volume_name);
213         if (dfs2->path == NULL)
214                 return False;
215         dfs2->comment = talloc_strdup(mem_ctx, j->comment);
216         dfs2->state = 1; /* set up state of dfs junction as OK */
217         dfs2->num_stores = j->referral_count;
218         return True;
219 }
220
221 static bool init_reply_dfs_info_3(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info3* dfs3)
222 {
223         int ii;
224         if (j->volume_name[0] == '\0')
225                 dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s",
226                         lp_netbios_name(), j->service_name);
227         else
228                 dfs3->path = talloc_asprintf(mem_ctx, "\\\\%s\\%s\\%s", lp_netbios_name(),
229                         j->service_name, j->volume_name);
230
231         if (dfs3->path == NULL)
232                 return False;
233
234         dfs3->comment = talloc_strdup(mem_ctx, j->comment);
235         dfs3->state = 1;
236         dfs3->num_stores = j->referral_count;
237
238         /* also enumerate the stores */
239         if (j->referral_count) {
240                 dfs3->stores = talloc_array(mem_ctx, struct dfs_StorageInfo, j->referral_count);
241                 if (!dfs3->stores)
242                         return False;
243                 memset(dfs3->stores, '\0', j->referral_count * sizeof(struct dfs_StorageInfo));
244         } else {
245                 dfs3->stores = NULL;
246         }
247
248         for(ii=0;ii<j->referral_count;ii++) {
249                 char* p;
250                 char *path = NULL;
251                 struct dfs_StorageInfo* stor = &(dfs3->stores[ii]);
252                 struct referral* ref = &(j->referral_list[ii]);
253
254                 path = talloc_strdup(mem_ctx, ref->alternate_path);
255                 if (!path) {
256                         return False;
257                 }
258                 trim_char(path,'\\','\0');
259                 p = strrchr_m(path,'\\');
260                 if(p==NULL) {
261                         DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path));
262                         continue;
263                 }
264                 *p = '\0';
265                 DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1));
266                 stor->state = 2; /* set all stores as ONLINE */
267                 stor->server = talloc_strdup(mem_ctx, path);
268                 stor->share = talloc_strdup(mem_ctx, p+1);
269         }
270         return True;
271 }
272
273 static bool init_reply_dfs_info_100(TALLOC_CTX *mem_ctx, struct junction_map* j, struct dfs_Info100* dfs100)
274 {
275         dfs100->comment = talloc_strdup(mem_ctx, j->comment);
276         return True;
277 }
278
279 WERROR _dfs_Enum(struct pipes_struct *p, struct dfs_Enum *r)
280 {
281         struct junction_map *jn = NULL;
282         size_t num_jn = 0;
283         size_t i;
284         TALLOC_CTX *ctx = talloc_tos();
285
286         jn = enum_msdfs_links(ctx, &num_jn);
287         if (!jn || num_jn == 0) {
288                 num_jn = 0;
289                 jn = NULL;
290         }
291
292         DEBUG(5,("_dfs_Enum: %u junctions found in Dfs, doing level %d\n",
293                                 (unsigned int)num_jn, r->in.level));
294
295         *r->out.total = num_jn;
296
297         /* Create the return array */
298         switch (r->in.level) {
299         case 1:
300                 if (num_jn) {
301                         if ((r->out.info->e.info1->s = talloc_array(ctx, struct dfs_Info1, num_jn)) == NULL) {
302                                 return WERR_NOMEM;
303                         }
304                 } else {
305                         r->out.info->e.info1->s = NULL;
306                 }
307                 r->out.info->e.info1->count = num_jn;
308                 break;
309         case 2:
310                 if (num_jn) {
311                         if ((r->out.info->e.info2->s = talloc_array(ctx, struct dfs_Info2, num_jn)) == NULL) {
312                                 return WERR_NOMEM;
313                         }
314                 } else {
315                         r->out.info->e.info2->s = NULL;
316                 }
317                 r->out.info->e.info2->count = num_jn;
318                 break;
319         case 3:
320                 if (num_jn) {
321                         if ((r->out.info->e.info3->s = talloc_array(ctx, struct dfs_Info3, num_jn)) == NULL) {
322                                 return WERR_NOMEM;
323                         }
324                 } else {
325                         r->out.info->e.info3->s = NULL;
326                 }
327                 r->out.info->e.info3->count = num_jn;
328                 break;
329         default:
330                 return WERR_INVALID_PARAM;
331         }
332
333         for (i = 0; i < num_jn; i++) {
334                 switch (r->in.level) {
335                 case 1:
336                         init_reply_dfs_info_1(ctx, &jn[i], &r->out.info->e.info1->s[i]);
337                         break;
338                 case 2:
339                         init_reply_dfs_info_2(ctx, &jn[i], &r->out.info->e.info2->s[i]);
340                         break;
341                 case 3:
342                         init_reply_dfs_info_3(ctx, &jn[i], &r->out.info->e.info3->s[i]);
343                         break;
344                 default:
345                         return WERR_INVALID_PARAM;
346                 }
347         }
348
349         return WERR_OK;
350 }
351
352 WERROR _dfs_GetInfo(struct pipes_struct *p, struct dfs_GetInfo *r)
353 {
354         int consumedcnt = strlen(r->in.dfs_entry_path);
355         struct junction_map *jn = NULL;
356         bool self_ref = False;
357         TALLOC_CTX *ctx = talloc_tos();
358         bool ret;
359         NTSTATUS status;
360
361         jn = talloc_zero(ctx, struct junction_map);
362         if (!jn) {
363                 return WERR_NOMEM;
364         }
365
366         ret = create_junction(ctx, r->in.dfs_entry_path,
367                               true, /* allow broken_path */
368                               jn);
369         if (!ret) {
370                 return WERR_DFS_NO_SUCH_SERVER;
371         }
372
373         /* The following call can change the cwd. */
374         status = get_referred_path(ctx, r->in.dfs_entry_path,
375                                    true, /*allow_broken_path */
376                                    jn, &consumedcnt, &self_ref);
377         if(!NT_STATUS_IS_OK(status) ||
378                         consumedcnt < strlen(r->in.dfs_entry_path)) {
379                 return WERR_DFS_NO_SUCH_VOL;
380         }
381
382         switch (r->in.level) {
383                 case 1:
384                         r->out.info->info1 = talloc_zero(ctx,struct dfs_Info1);
385                         if (!r->out.info->info1) {
386                                 return WERR_NOMEM;
387                         }
388                         ret = init_reply_dfs_info_1(ctx, jn, r->out.info->info1);
389                         break;
390                 case 2:
391                         r->out.info->info2 = talloc_zero(ctx,struct dfs_Info2);
392                         if (!r->out.info->info2) {
393                                 return WERR_NOMEM;
394                         }
395                         ret = init_reply_dfs_info_2(ctx, jn, r->out.info->info2);
396                         break;
397                 case 3:
398                         r->out.info->info3 = talloc_zero(ctx,struct dfs_Info3);
399                         if (!r->out.info->info3) {
400                                 return WERR_NOMEM;
401                         }
402                         ret = init_reply_dfs_info_3(ctx, jn, r->out.info->info3);
403                         break;
404                 case 100:
405                         r->out.info->info100 = talloc_zero(ctx,struct dfs_Info100);
406                         if (!r->out.info->info100) {
407                                 return WERR_NOMEM;
408                         }
409                         ret = init_reply_dfs_info_100(ctx, jn, r->out.info->info100);
410                         break;
411                 default:
412                         r->out.info->info1 = NULL;
413                         return WERR_INVALID_PARAM;
414         }
415
416         if (!ret)
417                 return WERR_INVALID_PARAM;
418
419         return WERR_OK;
420 }
421
422 WERROR _dfs_SetInfo(struct pipes_struct *p, struct dfs_SetInfo *r)
423 {
424         /* FIXME: Implement your code here */
425         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
426         return WERR_NOT_SUPPORTED;
427 }
428
429 WERROR _dfs_Rename(struct pipes_struct *p, struct dfs_Rename *r)
430 {
431         /* FIXME: Implement your code here */
432         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
433         return WERR_NOT_SUPPORTED;
434 }
435
436 WERROR _dfs_Move(struct pipes_struct *p, struct dfs_Move *r)
437 {
438         /* FIXME: Implement your code here */
439         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
440         return WERR_NOT_SUPPORTED;
441 }
442
443 WERROR _dfs_ManagerGetConfigInfo(struct pipes_struct *p, struct dfs_ManagerGetConfigInfo *r)
444 {
445         /* FIXME: Implement your code here */
446         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
447         return WERR_NOT_SUPPORTED;
448 }
449
450 WERROR _dfs_ManagerSendSiteInfo(struct pipes_struct *p, struct dfs_ManagerSendSiteInfo *r)
451 {
452         /* FIXME: Implement your code here */
453         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
454         return WERR_NOT_SUPPORTED;
455 }
456
457 WERROR _dfs_AddFtRoot(struct pipes_struct *p, struct dfs_AddFtRoot *r)
458 {
459         /* FIXME: Implement your code here */
460         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
461         return WERR_NOT_SUPPORTED;
462 }
463
464 WERROR _dfs_RemoveFtRoot(struct pipes_struct *p, struct dfs_RemoveFtRoot *r)
465 {
466         /* FIXME: Implement your code here */
467         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
468         return WERR_NOT_SUPPORTED;
469 }
470
471 WERROR _dfs_AddStdRoot(struct pipes_struct *p, struct dfs_AddStdRoot *r)
472 {
473         /* FIXME: Implement your code here */
474         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
475         return WERR_NOT_SUPPORTED;
476 }
477
478 WERROR _dfs_RemoveStdRoot(struct pipes_struct *p, struct dfs_RemoveStdRoot *r)
479 {
480         /* FIXME: Implement your code here */
481         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
482         return WERR_NOT_SUPPORTED;
483 }
484
485 WERROR _dfs_ManagerInitialize(struct pipes_struct *p, struct dfs_ManagerInitialize *r)
486 {
487         /* FIXME: Implement your code here */
488         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
489         return WERR_NOT_SUPPORTED;
490 }
491
492 WERROR _dfs_AddStdRootForced(struct pipes_struct *p, struct dfs_AddStdRootForced *r)
493 {
494         /* FIXME: Implement your code here */
495         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
496         return WERR_NOT_SUPPORTED;
497 }
498
499 WERROR _dfs_GetDcAddress(struct pipes_struct *p, struct dfs_GetDcAddress *r)
500 {
501         /* FIXME: Implement your code here */
502         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
503         return WERR_NOT_SUPPORTED;
504 }
505
506 WERROR _dfs_SetDcAddress(struct pipes_struct *p, struct dfs_SetDcAddress *r)
507 {
508         /* FIXME: Implement your code here */
509         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
510         return WERR_NOT_SUPPORTED;
511 }
512
513 WERROR _dfs_FlushFtTable(struct pipes_struct *p, struct dfs_FlushFtTable *r)
514 {
515         /* FIXME: Implement your code here */
516         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
517         return WERR_NOT_SUPPORTED;
518 }
519
520 WERROR _dfs_Add2(struct pipes_struct *p, struct dfs_Add2 *r)
521 {
522         /* FIXME: Implement your code here */
523         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
524         return WERR_NOT_SUPPORTED;
525 }
526
527 WERROR _dfs_Remove2(struct pipes_struct *p, struct dfs_Remove2 *r)
528 {
529         /* FIXME: Implement your code here */
530         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
531         return WERR_NOT_SUPPORTED;
532 }
533
534 WERROR _dfs_EnumEx(struct pipes_struct *p, struct dfs_EnumEx *r)
535 {
536         /* FIXME: Implement your code here */
537         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
538         return WERR_NOT_SUPPORTED;
539 }
540
541 WERROR _dfs_SetInfo2(struct pipes_struct *p, struct dfs_SetInfo2 *r)
542 {
543         /* FIXME: Implement your code here */
544         p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;
545         return WERR_NOT_SUPPORTED;
546 }