Fixes to get ms-dfs code to compile with the new changes.
[ira/wip.git] / source3 / rpc_server / srv_dfs.c
1 /* 
2  *  Unix SMB/Netbios implementation.
3  *  Version 1.9.
4  *  RPC Pipe client / server routines for Dfs
5  *  Copyright (C) Andrew Tridgell              1992-1997,
6  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
7  *  Copyright (C) Shirish Kalele               2000.
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 "nterr.h"
26
27 #define MAX_MSDFS_JUNCTIONS 256
28
29 extern int DEBUGLEVEL;
30 extern pstring global_myname;
31
32 #ifdef WITH_MSDFS
33
34 /**********************************************************************
35  api_dfs_exist
36  **********************************************************************/
37 static BOOL api_dfs_exist(pipes_struct *p)
38 {
39         DFS_R_DFS_EXIST r_d;
40         prs_struct *rdata = &p->out_data.rdata;
41
42         if(lp_host_msdfs()) 
43                 r_d.dfs_exist_flag = 1;
44         else
45                 r_d.dfs_exist_flag = 0; 
46         
47         return dfs_io_r_dfs_exist("", &r_d, rdata, 0);
48 }
49
50 static uint32 init_reply_dfs_add(DFS_Q_DFS_ADD* q_a)
51 {
52   struct junction_map jn;
53   struct referral* old_referral_list = NULL;
54   BOOL exists = False;
55
56   pstring dfspath, servername, sharename;
57   pstring altpath;
58
59   unistr2_to_ascii(dfspath, &(q_a->DfsEntryPath), sizeof(dfspath)-1);
60   unistr2_to_ascii(servername, &(q_a->ServerName), sizeof(servername)-1);
61   unistr2_to_ascii(sharename, &(q_a->ShareName), sizeof(sharename)-1);
62
63   DEBUG(5,("init_reply_dfs_add: Request to add %s -> %s\\%s.\n",
64            dfspath, servername, sharename));
65
66   pstrcpy(altpath, servername);
67   pstrcat(altpath, "\\");
68   pstrcat(altpath, sharename);
69
70   if(!create_junction(dfspath, &jn))
71     return NERR_DfsNoSuchServer;
72
73   if(get_referred_path(&jn))
74     {
75       exists = True;
76       jn.referral_count += 1;
77       old_referral_list = jn.referral_list;
78     }
79   else
80     jn.referral_count = 1;
81
82   jn.referral_list = (struct referral*) malloc(jn.referral_count 
83                                                * sizeof(struct referral));
84
85   if(jn.referral_list == NULL)
86     {
87       DEBUG(0,("init_reply_dfs_add: malloc failed for referral list!\n"));
88       return NERR_DfsInternalError;
89     }
90
91   if(old_referral_list)
92     {
93       memcpy(jn.referral_list, old_referral_list, 
94              sizeof(struct referral)*jn.referral_count-1);
95       free(old_referral_list);
96     }
97   
98   jn.referral_list[jn.referral_count-1].proximity = 0;
99   jn.referral_list[jn.referral_count-1].ttl = REFERRAL_TTL;
100
101   pstrcpy(jn.referral_list[jn.referral_count-1].alternate_path, altpath);
102   
103   if(!create_msdfs_link(&jn, exists))
104     return NERR_DfsCantCreateJunctionPoint;
105
106   return 0;
107 }
108 /*****************************************************************
109  api_dfs_add
110  *****************************************************************/
111 static BOOL api_dfs_add(pipes_struct *p)
112 {
113         DFS_Q_DFS_ADD q_a;
114         DFS_R_DFS_ADD r_a;
115         prs_struct *data = &p->in_data.data;
116         prs_struct *rdata = &p->out_data.rdata;
117
118         if(!dfs_io_q_dfs_add("", &q_a, data, 0))
119                 return False;
120         
121         r_a.status = init_reply_dfs_add(&q_a);
122         
123         dfs_io_r_dfs_add("", &r_a, rdata, 0);
124         
125         return True;
126 }
127
128 static uint32 init_reply_dfs_remove(DFS_Q_DFS_REMOVE* q_r)
129 {
130   struct junction_map jn;
131   BOOL found = False;
132
133   pstring dfspath, servername, sharename;
134   pstring altpath;
135
136   unistr2_to_ascii(dfspath, &(q_r->DfsEntryPath), sizeof(dfspath)-1);
137   if(q_r->ptr_ServerName)
138     unistr2_to_ascii(servername, &(q_r->ServerName), sizeof(servername)-1);
139
140   if(q_r->ptr_ShareName)
141     unistr2_to_ascii(sharename, &(q_r->ShareName), sizeof(sharename)-1);
142
143   if(q_r->ptr_ServerName && q_r->ptr_ShareName)
144     {
145       pstrcpy(altpath, servername);
146       pstrcat(altpath, "\\");
147       pstrcat(altpath, sharename);
148     }
149
150   DEBUG(5,("init_reply_dfs_remove: Request to remove %s -> %s\\%s.\n",
151            dfspath, servername, sharename));
152
153   if(!create_junction(dfspath, &jn))
154     return NERR_DfsNoSuchServer;
155
156   if(!get_referred_path(&jn))
157     return NERR_DfsNoSuchVolume;
158
159   /* if no server-share pair given, remove the msdfs link completely */
160   if(!q_r->ptr_ServerName && !q_r->ptr_ShareName)
161     {
162       if(!remove_msdfs_link(&jn))
163         return NERR_DfsNoSuchVolume;
164     }
165   else
166     {
167       int i=0;
168       /* compare each referral in the list with the one to remove */
169       for(i=0;i<jn.referral_count;i++)
170         {
171           pstring refpath;
172           pstrcpy(refpath,jn.referral_list[i].alternate_path);
173           trim_string(refpath, "\\", "\\");
174           if(strequal(refpath, altpath))
175             {
176               *(jn.referral_list[i].alternate_path)='\0';
177               found = True;
178             }
179         }
180       if(!found)
181         return NERR_DfsNoSuchShare;
182       
183       /* Only one referral, remove it */
184       if(jn.referral_count == 1)
185         {
186           if(!remove_msdfs_link(&jn))
187             return NERR_DfsNoSuchVolume;
188         }
189       else
190         {
191           if(!create_msdfs_link(&jn, True))
192             return NERR_DfsCantCreateJunctionPoint;
193         }
194     }
195
196   return 0;
197 }
198
199 /*****************************************************************
200  api_dfs_remove
201  *****************************************************************/
202 static BOOL api_dfs_remove(pipes_struct *p)
203 {
204         DFS_Q_DFS_REMOVE q_r;
205         DFS_R_DFS_REMOVE r_r;
206         prs_struct *data = &p->in_data.data;
207         prs_struct *rdata = &p->out_data.rdata;
208         
209         if(!dfs_io_q_dfs_remove("", &q_r, data, 0))
210                 return False;
211         
212         r_r.status = init_reply_dfs_remove(&q_r);
213         
214         dfs_io_r_dfs_remove("", &r_r, rdata, 0);
215         
216         return True;
217 }
218
219 static BOOL init_reply_dfs_info_1(struct junction_map* j, DFS_INFO_1* dfs1, int num_j)
220 {
221   int i=0;
222   for(i=0;i<num_j;i++) 
223     {
224       pstring str;
225       dfs1[i].ptr_entrypath = 1;
226       slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname, 
227                j[i].service_name, j[i].volume_name);
228       DEBUG(5,("init_reply_dfs_info_1: %d) initing entrypath: %s\n",i,str));
229       init_unistr2(&dfs1[i].entrypath,str,strlen(str)+1);
230     }
231   return True;
232 }
233
234 static BOOL init_reply_dfs_info_2(struct junction_map* j, DFS_INFO_2* dfs2, int num_j)
235 {
236   int i=0;
237   for(i=0;i<num_j;i++)
238     {
239       pstring str;
240       dfs2[i].ptr_entrypath = 1;
241       slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname,
242                j[i].service_name, j[i].volume_name);
243       init_unistr2(&dfs2[i].entrypath, str, strlen(str)+1);
244       dfs2[i].ptr_comment = 0;
245       dfs2[i].state = 1; /* set up state of dfs junction as OK */
246       dfs2[i].num_storages = j[i].referral_count;
247     }
248   return True;
249 }
250
251 static BOOL init_reply_dfs_info_3(struct junction_map* j, DFS_INFO_3* dfs3, int num_j)
252 {
253   int i=0,ii=0;
254   for(i=0;i<num_j;i++)
255     {
256       pstring str;
257       dfs3[i].ptr_entrypath = 1;
258       slprintf(str, sizeof(pstring)-1, "\\\\%s\\%s\\%s", global_myname,
259                j[i].service_name, j[i].volume_name);
260       init_unistr2(&dfs3[i].entrypath, str, strlen(str)+1);
261       dfs3[i].ptr_comment = 1;
262       init_unistr2(&dfs3[i].comment, "", 1); 
263       dfs3[i].state = 1;
264       dfs3[i].num_storages = dfs3[i].num_storage_infos = j[i].referral_count;
265       dfs3[i].ptr_storages = 1;
266      
267       /* also enumerate the storages */
268       dfs3[i].storages = (DFS_STORAGE_INFO*) malloc(j[i].referral_count * 
269                                                     sizeof(DFS_STORAGE_INFO));
270       for(ii=0;ii<j[i].referral_count;ii++)
271         {
272           char* p; 
273           pstring path;
274           DFS_STORAGE_INFO* stor = &(dfs3[i].storages[ii]);
275           struct referral* ref = &(j[i].referral_list[ii]);
276           
277           pstrcpy(path, ref->alternate_path);
278           trim_string(path,"\\","");
279           p = strrchr(path,'\\');
280           if(p==NULL)
281             {
282               DEBUG(4,("init_reply_dfs_info_3: invalid path: no \\ found in %s\n",path));
283               continue;
284             }
285           *p = '\0';
286           DEBUG(5,("storage %d: %s.%s\n",ii,path,p+1));
287           stor->state = 2; /* set all storages as ONLINE */
288           init_unistr2(&stor->servername, path, strlen(path)+1);
289           init_unistr2(&stor->sharename,  p+1, strlen(p+1)+1);
290           stor->ptr_servername = stor->ptr_sharename = 1;
291         }
292     }
293   return True;
294 }
295
296 static uint32 init_reply_dfs_ctr(uint32 level, DFS_INFO_CTR* ctr, 
297                                struct junction_map* jn, int num_jn)
298 {
299   /* do the levels */
300   switch(level)
301     {
302     case 1:
303       {
304         DFS_INFO_1* dfs1;
305         dfs1 = (DFS_INFO_1*) malloc(num_jn * sizeof(DFS_INFO_1));
306         init_reply_dfs_info_1(jn, dfs1, num_jn);
307         ctr->dfs.info1 = dfs1;
308         break;
309       }
310     case 2:
311       {
312         DFS_INFO_2* dfs2;
313         dfs2 = (DFS_INFO_2*) malloc(num_jn * sizeof(DFS_INFO_2));
314         init_reply_dfs_info_2(jn, dfs2, num_jn);
315         ctr->dfs.info2 = dfs2;
316         break;
317       }
318     case 3:
319       {
320         DFS_INFO_3* dfs3;
321         dfs3 = (DFS_INFO_3*) malloc(num_jn * sizeof(DFS_INFO_3));
322         init_reply_dfs_info_3(jn, dfs3, num_jn);
323         ctr->dfs.info3 = dfs3;
324       }
325     }
326   return 0;
327 }
328       
329 static uint32 init_reply_dfs_enum(uint32 level, DFS_R_DFS_ENUM *q_r)
330 {
331   struct junction_map jn[MAX_MSDFS_JUNCTIONS];
332   int num_jn = 0;
333   int i=0;
334
335   num_jn = enum_msdfs_links(jn);
336   
337   DEBUG(5,("make_reply_dfs_enum: %d junctions found in Dfs, doing level %d\n",
338            num_jn, level));
339
340   q_r->ptr_buffer = level;
341   q_r->level = q_r->level2 = level;
342   q_r->ptr_num_entries = q_r->ptr_num_entries2 = 1;
343   q_r->num_entries = q_r->num_entries2 = num_jn;
344   q_r->reshnd.ptr_hnd = 1;
345   q_r->reshnd.handle = num_jn;
346   
347   q_r->ctr = (DFS_INFO_CTR*) malloc(sizeof(DFS_INFO_CTR));
348   q_r->ctr->switch_value = level;
349   q_r->ctr->num_entries = num_jn;
350   q_r->ctr->ptr_dfs_ctr = 1;
351   
352   init_reply_dfs_ctr(level, q_r->ctr, jn, num_jn);
353
354   for(i=0;i<num_jn;i++)
355     free(jn[i].referral_list);
356
357   return 0;
358 }
359       
360 static uint32 init_reply_dfs_get_info(UNISTR2* uni_path, uint32 level,  
361                                       DFS_R_DFS_GET_INFO* r_i)
362 {
363   pstring path;
364   struct junction_map jn;
365
366   unistr2_to_ascii(path, uni_path, sizeof(path)-1);
367   if(!create_junction(path, &jn))
368      return NERR_DfsNoSuchServer;
369   
370   if(!get_referred_path(&jn))
371     return NERR_DfsNoSuchVolume;
372
373   r_i->level = level;
374   r_i->ptr_ctr = 1;
375   r_i->status = init_reply_dfs_ctr(level, &(r_i->ctr), &jn, 1);
376   
377   free(jn.referral_list);
378   return 0;
379 }
380 /*******************************************************************
381  api_dfs_get_info
382  *******************************************************************/
383 static BOOL api_dfs_get_info(pipes_struct *p)
384 {
385         DFS_Q_DFS_GET_INFO q_i;
386         DFS_R_DFS_GET_INFO r_i;
387         prs_struct *data = &p->in_data.data;
388         prs_struct *rdata = &p->out_data.rdata;
389
390         ZERO_STRUCT(r_i);
391         
392         if(!dfs_io_q_dfs_get_info("", &q_i, data, 0))
393                 return False;
394         
395         r_i.status = init_reply_dfs_get_info(&q_i.uni_path, q_i.level, &r_i);
396         
397         if(!dfs_io_r_dfs_get_info("", &r_i, rdata, 0))
398                 return False;
399         
400         switch(r_i.level) {
401         case 1: free(r_i.ctr.dfs.info1); break;
402         case 2: free(r_i.ctr.dfs.info2); break;
403         case 3: {
404                 free(r_i.ctr.dfs.info3->storages);
405                 free(r_i.ctr.dfs.info3);
406                 break;
407         }
408         }
409         return True;
410 }
411
412 /*******************************************************************
413  api_dfs_enum
414  *******************************************************************/
415 static BOOL api_dfs_enum(pipes_struct *p)
416 {
417         DFS_Q_DFS_ENUM q_e;
418         DFS_R_DFS_ENUM q_r;
419         prs_struct *data = &p->in_data.data;
420         prs_struct *rdata = &p->out_data.rdata;
421
422         if(!dfs_io_q_dfs_enum("", &q_e, data, 0))
423                 return False;
424         
425         q_r.status = init_reply_dfs_enum(q_e.level, &q_r);
426         
427         if(!dfs_io_r_dfs_enum("", &q_r, rdata, 0))
428                 return False;
429         switch(q_e.level) {
430         case 1: 
431                 free(q_r.ctr->dfs.info1); break;
432         case 2:
433                 free(q_r.ctr->dfs.info2); break;
434         case 3:
435                 free(q_r.ctr->dfs.info3->storages); 
436                 free(q_r.ctr->dfs.info3); break;
437         }
438         free(q_r.ctr);
439         return True;
440 }
441
442 /*******************************************************************
443 \pipe\netdfs commands
444 ********************************************************************/
445 struct api_struct api_netdfs_cmds[] =
446 {
447         {"DFS_EXIST",        DFS_EXIST,               api_dfs_exist    },
448         {"DFS_ADD",          DFS_ADD,                 api_dfs_add      },
449         {"DFS_REMOVE",       DFS_REMOVE,              api_dfs_remove   },
450         {"DFS_GET_INFO",     DFS_GET_INFO,            api_dfs_get_info },
451         {"DFS_ENUM",         DFS_ENUM,                api_dfs_enum     },
452         {NULL,               0,                       NULL             }
453 };
454
455 /*******************************************************************
456 receives a netdfs pipe and responds.
457 ********************************************************************/
458 BOOL api_netdfs_rpc(pipes_struct *p)
459 {
460         return api_rpcTNP(p, "api_netdfs_rpc", api_netdfs_cmds);
461 }
462
463 #endif