1 /* usmb - mount SMB shares via FUSE and Samba
2 * Copyright (C) 2006-2010 Geoff Johnstone
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <sys/time.h> // struct timeval needed by libsmbclient.h
20 #include <libsmbclient.h>
21 #include "samba3x-compat.h"
37 #include "usmb_file.h"
43 static char *server
, *share
, *mountpoint
, *options
,
44 *domain
, *username
, *password
;
47 char * make_url (const char *path
)
49 assert (NULL
!= share
);
51 if ((NULL
== path
) || ('\0' == path
[0]))
52 return xstrdup (share
);
54 return concat_strings (2, share
, path
);
58 static inline void do_strncpy (char *to
, const char *from
, int tolen
)
60 strncpy (to
, from
, tolen
);
65 static void auth_fn (const char *srv UNUSED
, const char *shr UNUSED
,
66 char *wg
, int wglen
, char *un
, int unlen
,
69 DEBUG (fprintf (stderr
, "Authenticating for \\\\%s\\%s\n", srv
, shr
));
70 DEBUG (fprintf (stderr
, "Domain: %s; User: %s; Password: %s\n",
71 domain
, username
, password
));
74 do_strncpy (wg
, domain
, wglen
);
76 do_strncpy (un
, username
, unlen
);
77 do_strncpy (pw
, password
, pwlen
);
81 void destroy_smb_context (SMBCCTX
*ctx_
, int shutdown
)
83 // Samba frees the workgroup and user strings but we want to persist them.
84 smbc_setWorkgroup (ctx_
, NULL
);
85 smbc_setUser (ctx_
, NULL
);
86 smbc_free_context (ctx_
, shutdown
);
90 bool create_smb_context (SMBCCTX
**pctx
)
92 *pctx
= smbc_new_context();
96 perror ("Cannot create SMB context");
100 smbc_setWorkgroup (*pctx
, domain
);
101 smbc_setUser (*pctx
, username
);
102 smbc_setTimeout (*pctx
, 5000);
103 smbc_setFunctionAuthData (*pctx
, auth_fn
);
105 if (NULL
== smbc_init_context (*pctx
))
107 perror ("Cannot initialise SMB context");
108 destroy_smb_context (*pctx
, 1);
116 static void * usmb_init (struct fuse_conn_info
*conn UNUSED
)
118 DEBUG (fputs ("usmb_init()\n", stderr
));
123 static void usmb_destroy (void *unused UNUSED
)
125 DEBUG (fputs ("usmb_destroy()\n", stderr
));
129 // probably won't (can't ?) implement these:
130 // readlink mknod symlink flush fsync
132 // no easy way of implementing these:
136 #define SET_ELEMENT(name,value) value
138 #define SET_ELEMENT(name,value) name = value
140 static struct fuse_operations fuse_ops
= {
141 SET_ELEMENT (.getattr
, usmb_getattr
),
142 SET_ELEMENT (.readlink
, NULL
),
143 SET_ELEMENT (.getdir
, NULL
),
144 SET_ELEMENT (.mknod
, NULL
),
145 SET_ELEMENT (.mkdir
, usmb_mkdir
),
146 SET_ELEMENT (.unlink
, usmb_unlink
),
147 SET_ELEMENT (.rmdir
, usmb_rmdir
),
148 SET_ELEMENT (.symlink
, NULL
),
149 SET_ELEMENT (.rename
, usmb_rename
),
150 SET_ELEMENT (.link
, NULL
),
151 SET_ELEMENT (.chmod
, usmb_chmod
),
152 SET_ELEMENT (.chown
, NULL
), // usmb_chown, --not implemented in libsmbclient
153 SET_ELEMENT (.truncate
, usmb_truncate
),
154 SET_ELEMENT (.utime
, usmb_utime
),
155 SET_ELEMENT (.open
, usmb_open
),
156 SET_ELEMENT (.read
, usmb_read
),
157 SET_ELEMENT (.write
, usmb_write
),
158 SET_ELEMENT (.statfs
, usmb_statfs
),
159 SET_ELEMENT (.flush
, NULL
),
160 SET_ELEMENT (.release
, usmb_release
),
161 SET_ELEMENT (.fsync
, NULL
),
162 SET_ELEMENT (.setxattr
, usmb_setxattr
),
163 SET_ELEMENT (.getxattr
, usmb_getxattr
),
164 SET_ELEMENT (.listxattr
, usmb_listxattr
),
165 SET_ELEMENT (.removexattr
, usmb_removexattr
),
166 SET_ELEMENT (.opendir
, usmb_opendir
),
167 SET_ELEMENT (.readdir
, usmb_readdir
),
168 SET_ELEMENT (.releasedir
, usmb_releasedir
),
169 SET_ELEMENT (.fsyncdir
, NULL
),
170 SET_ELEMENT (.init
, usmb_init
),
171 SET_ELEMENT (.destroy
, usmb_destroy
),
172 SET_ELEMENT (.access
, NULL
),
173 SET_ELEMENT (.create
, usmb_create
),
174 SET_ELEMENT (.ftruncate
, usmb_ftruncate
),
175 SET_ELEMENT (.fgetattr
, usmb_fgetattr
),
176 SET_ELEMENT (.lock
, NULL
), // TODO: implement
177 SET_ELEMENT (.utimens
, NULL
), // TODO: implement
178 SET_ELEMENT (.bmap
, NULL
), // TODO: implement
182 static bool create_share_name (const char *server_
, const char *sharename
)
184 size_t len
= strlen ("smb:///") +
186 strlen (sharename
) + 1;
188 if (NULL
== (share
= malloc (len
)))
190 perror ("Cannot allocate share name");
194 if (!bsnprintf (share
, len
, "smb://%s/%s", server_
, sharename
))
196 fputs ("Share server and/or name are too long.\n", stderr
);
201 DEBUG (fprintf (stderr
, "Share URL: %s\n", share
));
206 static void free_strings (char *sharename
)
209 clear_and_free (password
);
219 static bool check_credentials (void)
221 char *url
= make_url ("");
228 DEBUG (fprintf (stderr
, "URL: %s\n", url
));
231 bool ret
= (0 == (smbc_getFunctionStat (ctx
) (ctx
, url
, &stat_
)));
238 static bool get_context (void)
242 unsigned attempts
= 3;
244 while (0 != attempts
--)
246 if ((NULL
== password
) && !password_read (&password
))
249 if (!create_smb_context (&ctx
))
251 clear_and_free (password
);
257 if (check_credentials())
260 perror ("Connection failed");
261 clear_and_free (password
);
264 destroy_smb_context (ctx
, 1);
268 return (NULL
!= ctx
);
272 int main (int argc
, char **argv
)
274 const char *conffile
, *mountid
;
276 char *sharename
= NULL
;
277 int ret
= EXIT_FAILURE
;
279 if (sizeof (uint64_t) < sizeof (uintptr_t))
281 fputs ("usmb is not supported on this platform.\n", stderr
);
286 static char conf
[PATH_MAX
];
287 const char * const HOME
= getenv ("HOME");
290 fputs ("Please set the HOME environment variable.\n", stderr
);
294 if (!bsnprintf (conf
, sizeof (conf
), "%s/.usmb.conf", HOME
))
296 fputs ("Configuration file path is too long.\n", stderr
);
303 if (!parse_args (&argc
, &argv
, &mountid
, &conffile
, &umount
))
309 if (!conffile_get_mount (conffile
, mountid
,
310 &server
, &sharename
, &mountpoint
, &options
,
311 &domain
, &username
, &password
))
314 DEBUG (fprintf (stderr
, "Mountpoint: %s\n", mountpoint
));
318 execlp ("fusermount", "fusermount", "-u", mountpoint
, NULL
);
319 perror ("Failed to execute fusermount");
322 else if (create_share_name (server
, sharename
) && get_context())
324 DEBUG (fprintf (stderr
, "Username: %s\\%s\n", domain
, username
));
328 build_fuse_args (options
, mountpoint
, &fuse_argc
, &fuse_argv
);
329 ret
= fuse_main (fuse_argc
, fuse_argv
, &fuse_ops
, NULL
);
330 destroy_smb_context (ctx
, 1);
333 free_strings (sharename
);