Add early prototype of cifs mount helper for Linux
[Samba/wip.git] / source3 / client / mount.cifs.c
blob5b19752f8bfe9bfa3b06a5c0c0f173449432e0d7
1 #define _GNU_SOURCE
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <pwd.h>
6 #include <sys/types.h>
7 #include <sys/mount.h>
8 #include <sys/stat.h>
9 #include <sys/utsname.h>
10 #include <sys/socket.h>
11 #include <arpa/inet.h>
12 #include <getopt.h>
13 #include <errno.h>
14 #include <netdb.h>
15 #include <string.h>
17 #define MOUNT_CIFS_VERSION "1"
19 extern char *getusername(void);
21 char * thisprogram;
22 int verboseflag = 0;
23 static int got_password = 0;
24 static int got_user = 0;
25 static char * user_name = NULL;
26 char * mountpassword = NULL;
29 void mount_cifs_usage()
31 printf("\nUsage: %s remotetarget dir\n", thisprogram);
32 printf("\nMount the remotetarget, specified as either a UNC name or ");
33 printf(" CIFS URL, to the local directory, dir.\n");
35 return;
38 /* caller frees username if necessary */
39 char * getusername() {
40 char *username = NULL;
41 struct passwd *password = getpwuid(getuid());
43 if (password) {
44 username = password->pw_name;
46 return username;
49 char * parse_cifs_url(unc_name)
51 printf("\ncifs url %s\n",unc_name);
54 char * parse_options(char * options)
56 /* BB add missing code BB */
59 /* Note that caller frees the returned buffer if necessary */
60 char * parse_server(char * unc_name)
62 int length = strnlen(unc_name,1024);
63 char * share;
64 char * ipaddress_string = NULL;
65 struct hostent * host_entry;
66 struct in_addr server_ipaddr;
67 int rc,j;
68 char temp[64];
71 if(length > 1023) {
72 printf("mount error: UNC name too long");
73 return 0;
75 if (strncasecmp("cifs://",unc_name,7) == 0)
76 return parse_cifs_url(unc_name+7);
77 if (strncasecmp("smb://",unc_name,6) == 0) {
78 return parse_cifs_url(unc_name+6);
81 if(length < 3) {
82 /* BB add code to find DFS root here */
83 printf("\nMounting the DFS root for domain not implemented yet");
84 return 0;
85 } else {
86 /* BB add support for \\\\ not just // */
87 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
88 printf("mount error: improperly formatted UNC name.");
89 printf(" %s does not begin with \\\\ or //\n",unc_name);
90 return 0;
91 } else {
92 unc_name += 2;
93 if (share = strchr(unc_name, '/')) {
94 *share = 0; /* temporarily terminate the string */
95 share += 1;
96 host_entry = gethostbyname(unc_name);
97 *(share - 1) = '\\'; /* put the slash back */
98 /* rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
99 if(host_entry == NULL) {
100 printf("mount error: could not find target server. TCP name %s not found ", unc_name);
101 printf(" rc = %d\n",rc);
102 return 0;
104 else {
105 printf("Target server %s %x found\n",host_entry->h_name,host_entry->h_addr); /* BB removeme */
106 /* BB should we pass an alternate version of the share name as Unicode */
107 /* BB what about ipv6? BB */
108 /* BB add retries with alternate servers in list */
110 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
112 ipaddress_string = inet_ntoa(server_ipaddr);
113 if(ipaddress_string == NULL) {
114 printf("mount error: could not get valid ip address for target server\n");
115 return 0;
117 return ipaddress_string;
119 } else {
120 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
121 printf("Mounting the DFS root for a particular server not implemented yet\n");
122 return 0;
128 static struct option longopts[] = {
129 { "all", 0, 0, 'a' },
130 { "help", 0, 0, 'h' },
131 { "read-only", 0, 0, 'r' },
132 { "ro", 0, 0, 'r' },
133 { "verbose", 0, 0, 'v' },
134 { "version", 0, 0, 'V' },
135 { "read-write", 0, 0, 'w' },
136 { "rw", 0, 0, 'w' },
137 { "options", 1, 0, 'o' },
138 { "types", 1, 0, 't' },
139 { "replace", 0, 0, 129 },
140 { "after", 0, 0, 130 },
141 { "before", 0, 0, 131 },
142 { "over", 0, 0, 132 },
143 { "move", 0, 0, 133 },
144 { "rsize",1, 0, 136 },
145 { "wsize",1, 0, 137 },
146 { "uid", 1, 0, 138},
147 { "gid", 1, 0, 139},
148 { "uuid",1,0,'U' },
149 { "user",1,0,140},
150 { "username",1,0,140},
151 { "dom",1,0,141},
152 { "domain",1,0,141},
153 { "password",1,0,142},
154 { NULL, 0, 0, 0 }
157 int main(int argc, char ** argv)
159 int c;
160 int flags = MS_MANDLOCK | MS_MGC_VAL;
161 char * orgoptions = NULL;
162 char * options;
163 char * share_name;
164 char * domain_name = NULL;
165 char * ipaddr;
166 char * mount_point;
167 char * uuid = NULL;
168 int rc,i;
169 int rsize = 0;
170 int wsize = 0;
171 int nomtab = 0;
172 int uid = 0;
173 int gid = 0;
174 int optlen = 0;
175 struct stat statbuf;
176 struct utsname sysinfo;
178 /* setlocale(LC_ALL, "");
179 bindtextdomain(PACKAGE, LOCALEDIR);
180 textdomain(PACKAGE); */
182 if(argc && argv) {
183 thisprogram = argv[0];
185 if(thisprogram == NULL)
186 thisprogram = "mount.cifs";
188 uname(&sysinfo);
189 #ifdef _GNU_SOURCE
190 printf(" node: %s machine: %s\n", sysinfo.nodename,sysinfo.machine);
191 #endif
192 mount_cifs_usage();
193 share_name = argv[1];
194 mount_point = argv[2];
195 /* add sharename in opts string as unc= parm */
197 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
198 longopts, NULL)) != -1) {
199 switch (c) {
200 /* case 'a':
201 ++mount_all;
202 break;
203 case 'f':
204 ++fake;
205 break;
206 case 'F':
207 ++optfork;
208 break; */
209 case 'h': /* help */
210 mount_cifs_usage ();
211 break;
212 /* case 'i':
213 external_allowed = 0;
214 break;
215 case 'l':
216 list_with_volumelabel = 1;
217 break;
218 case 'L':
219 volumelabel = optarg;
220 break; */
221 case 'n':
222 ++nomtab;
223 break;
224 case 'o':
225 if (orgoptions) {
226 orgoptions = strcat(orgoptions, ",");
227 orgoptions = strcat(orgoptions,optarg);
228 } else
229 orgoptions = strdup(optarg);
230 break;
232 /* case 'O':
233 if (test_opts)
234 test_opts = xstrconcat3(test_opts, ",", optarg);
235 else
236 test_opts = xstrdup(optarg);
237 break;*/
238 case 'r': /* mount readonly */
239 flags |= MS_RDONLY;;
240 break;
241 case 'U':
242 uuid = optarg;
243 break;
244 case 'v':
245 ++verboseflag;
246 break;
247 /* case 'V':
248 printf ("mount: %s\n", version);
249 exit (0);*/
250 case 'w':
251 flags &= ~MS_RDONLY;;
252 break;
253 /* case 0:
254 break;
256 case 128:
257 mounttype = MS_BIND;
258 break;
259 case 129:
260 mounttype = MS_REPLACE;
261 break;
262 case 130:
263 mounttype = MS_AFTER;
264 break;
265 case 131:
266 mounttype = MS_BEFORE;
267 break;
268 case 132:
269 mounttype = MS_OVER;
270 break;
271 case 133:
272 mounttype = MS_MOVE;
273 break;
274 case 135:
275 mounttype = (MS_BIND | MS_REC);
276 break; */
277 case 136:
278 rsize = atoi(optarg) ;
279 break;
280 case 137:
281 wsize = atoi(optarg);
282 break;
283 case 138:
284 uid = atoi(optarg);
285 break;
286 case 139:
287 gid = atoi(optarg);
288 break;
289 case 140:
290 got_user = 1;
291 user_name = optarg;
292 break;
293 case 141:
294 domain_name = optarg;
295 break;
296 case 142:
297 got_password = 1;
298 mountpassword = optarg;
299 break;
300 case '?':
301 default:
302 mount_cifs_usage ();
306 for(i = 0;i < argc;i++) /* BB remove */
307 printf("\narg %d is %s",i,argv[i]); /* BB remove */
308 printf("\n"); /* BB removeme */
310 /* canonicalize the path in argv[1]? */
312 if(stat (mount_point, &statbuf)) {
313 printf("mount error: mount point %s does not exist\n",mount_point);
314 return -1;
316 if (S_ISDIR(statbuf.st_mode) == 0) {
317 printf("mount error: mount point %s is not a directory\n",mount_point);
318 return -1;
321 if(geteuid()) {
322 printf("mount error: permission denied, not superuser and cifs.mount not installed SUID\n");
323 return -1;
326 ipaddr = parse_server(share_name);
327 /* if(share_name == NULL)
328 return 1; */
329 parse_options(orgoptions);
331 if(got_user == 0)
332 user_name = getusername();
334 /* check username for user%password format */
336 if(got_password == 0) {
337 if (getenv("PASSWD")) {
338 mountpassword = malloc(33);
339 if(mountpassword) {
340 strncpy(mountpassword,getenv("PASSWD"),32);
341 got_password = 1;
343 /* } else if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
344 get_password_file();
345 got_password = 1;*/ /* BB add missing function */
346 } else {
347 mountpassword = getpass("Password: "); /* BB obsolete */
348 got_password = 1;
352 /* launch daemon (handles dfs name resolution and credential change) */
353 if(orgoptions)
354 optlen = strlen(orgoptions);
355 else
356 optlen = 0;
357 options = malloc(optlen + 25 + strlen(share_name) + strlen(user_name)
358 + strlen(ipaddr) + 1);
359 strcpy(options,"unc=");
360 strcat(options,share_name);
361 strncat(options,",ip=",4);
362 strcat(options,ipaddr);
363 strncat(options,",user=",6);
364 strcat(options,user_name);
365 strncat(options,",pass=",6);
366 strcat(options,mountpassword);
367 strncat(options,",ver=",5);
368 strcat(options,MOUNT_CIFS_VERSION);
369 if(optlen)
370 strcat(options,orgoptions);
371 printf("\noptions %s \n",options);
372 if(mount(share_name, mount_point, "cifs", flags, options)) {
373 /* remember to kill daemon on error */
374 switch (errno) {
375 case 0:
376 printf(" success\n"); /* BB removeme */
377 return 0;
378 case ENODEV:
379 printf("mount error: cifs filesystem not supported by the system\n");
380 break;
381 default:
382 printf("mount error %d = %s",errno,strerror(errno));
384 printf("\nRefer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
385 return -1;
386 } else
387 printf(" mount succeeded\n"); /* BB removeme */