1 /* SMB protocol implementation */
8 #ifdef HAVE_LIBSMBCLIENT_H
9 #include <libsmbclient.h>
15 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
23 #include "cache/cache.h"
24 #include "config/options.h"
25 #include "intl/gettext/libintl.h"
26 #include "main/module.h"
27 #include "main/select.h"
28 #include "network/connection.h"
29 #include "network/socket.h"
30 #include "osdep/osdep.h"
31 #include "protocol/auth/auth.h"
32 #include "protocol/common.h"
33 #include "protocol/protocol.h"
34 #include "protocol/smb/smb.h"
35 #include "protocol/uri.h"
36 #include "util/conv.h"
37 #include "util/memory.h"
38 #include "util/string.h"
40 /* These options are not used. */
42 struct option_info smb_options
[] = {
43 INIT_OPT_TREE("protocol", N_("SMB"),
45 N_("SAMBA specific options.")),
47 INIT_OPT_STRING("protocol.smb", N_("Credentials"),
49 N_("Credentials file passed to smbclient via -A option.")),
55 struct module smb_protocol_module
= struct_module(
56 /* name: */ N_("SMB"),
59 /* submodules: */ NULL
,
65 static FILE *header_out
, *data_out
;
67 /* The child process generally does not bother to free the memory it
68 * allocates. When the process exits, the operating system will free
69 * the memory anyway. There is no point in changing this, because the
70 * child process also inherits memory allocations from the parent
71 * process, and it would be very cumbersome to free those. */
76 fputs("text/x-error", header_out
);
77 fprintf(data_out
, "%d\n", error
);
82 compare(const void *a
, const void *b
)
84 const struct smbc_dirent
**da
= (const struct smbc_dirent
**)a
;
85 const struct smbc_dirent
**db
= (const struct smbc_dirent
**)b
;
86 int res
= (*da
)->smbc_type
- (*db
)->smbc_type
;
91 return strcmp((*da
)->name
, (*db
)->name
);
95 smb_add_link(struct string
*string
, const struct smbc_dirent
*entry
,
96 const unsigned char *text
, const unsigned char dircolor
[])
98 struct string uri_string
;
100 if (!init_string(&uri_string
)) return;
101 encode_uri_string(&uri_string
, entry
->name
, entry
->namelen
, 0);
103 add_to_string(string
, "<a href=\"");
104 add_html_to_string(string
, uri_string
.source
, uri_string
.length
);
105 done_string(&uri_string
);
107 add_to_string(string
, "\">");
109 add_to_string(string
, "<font color=\"");
110 add_to_string(string
, dircolor
);
111 add_to_string(string
, "\"><b>");
113 add_html_to_string(string
, entry
->name
, entry
->namelen
);
115 add_to_string(string
, "</b></font>");
117 add_to_string(string
, "</a>");
118 if (text
) add_to_string(string
, text
);
122 display_entry(const struct smbc_dirent
*entry
, const unsigned char dircolor
[])
124 static const unsigned char zero
= '\0';
125 struct string string
;
127 if (!init_string(&string
)) return;
129 switch (entry
->smbc_type
) {
131 smb_add_link(&string
, entry
, " WORKGROUP ", dircolor
);
134 smb_add_link(&string
, entry
, " SERVER ", dircolor
);
135 if (entry
->comment
) {
136 add_html_to_string(&string
, entry
->comment
, entry
->commentlen
);
139 case SMBC_FILE_SHARE
:
140 smb_add_link(&string
, entry
, " FILE SHARE ", dircolor
);
141 if (entry
->comment
) {
142 add_html_to_string(&string
, entry
->comment
, entry
->commentlen
);
145 case SMBC_PRINTER_SHARE
:
146 add_html_to_string(&string
, entry
->name
, entry
->namelen
);
147 add_to_string(&string
, " PRINTER ");
148 if (entry
->comment
) {
149 add_html_to_string(&string
, entry
->comment
, entry
->commentlen
);
152 case SMBC_COMMS_SHARE
:
153 add_bytes_to_string(&string
, entry
->name
, entry
->namelen
);
154 add_to_string(&string
, " COMM");
157 add_bytes_to_string(&string
, entry
->name
, entry
->namelen
);
158 add_to_string(&string
, " IPC");
161 smb_add_link(&string
, entry
, NULL
, dircolor
);
164 smb_add_link(&string
, entry
, " Link", &zero
);
167 smb_add_link(&string
, entry
, NULL
, &zero
);
173 fputs(string
.source
, data_out
);
174 fputc('\n', data_out
);
175 done_string(&string
);
179 sort_and_display_entries(int dir
, const unsigned char dircolor
[])
181 struct smbc_dirent
*fentry
, **table
= NULL
;
185 while ((fentry
= smbc_readdir(dir
))) {
186 struct smbc_dirent
**new_table
, *new_entry
;
187 unsigned int commentlen
= fentry
->commentlen
;
188 unsigned int namelen
= fentry
->namelen
;
190 if (!strcmp(fentry
->name
, "."))
193 /* In libsmbclient 3.0.10, @smbc_dirent.namelen and
194 * @smbc_dirent.commentlen include the null characters
195 * (tested with GDB). In libsmbclient 3.0.24, they
196 * don't. This is related to Samba bug 3030. Adjust
197 * the lengths to exclude the null characters, so that
198 * other code need not care.
200 * Make all changes to local copies rather than
201 * directly to *@fentry, so that there's no chance of
202 * ELinks messing up whatever mechanism libsmbclient
203 * will use to free @fentry. */
204 if (commentlen
> 0 && fentry
->comment
[commentlen
- 1] == '\0')
206 if (namelen
> 0 && fentry
->name
[namelen
- 1] == '\0')
209 /* libsmbclient seems to place the struct smbc_dirent,
210 * the name string, and the comment string all in one
211 * block of memory, which then is smbc_dirent.dirlen
212 * bytes long. This has however not been really
213 * documented, so ELinks should not assume copying
214 * fentry->dirlen bytes will copy the comment too.
215 * Yet, it would be wasteful to copy both dirlen bytes
216 * and then the comment string separately. What we do
217 * here is ignore fentry->dirlen and recompute the
218 * size based on namelen. */
219 new_entry
= (struct smbc_dirent
*)
220 memacpy((const unsigned char *) fentry
,
221 offsetof(struct smbc_dirent
, name
)
222 + namelen
); /* memacpy appends '\0' */
225 new_entry
->namelen
= namelen
;
226 new_entry
->commentlen
= commentlen
;
228 new_entry
->comment
= memacpy(fentry
->comment
, commentlen
);
229 if (!new_entry
->comment
)
230 new_entry
->commentlen
= 0;
232 new_table
= mem_realloc(table
, (size
+ 1) * sizeof(*table
));
236 table
[size
] = new_entry
;
239 /* If size==0, then table==NULL. According to ISO/IEC 9899:1999
240 * 7.20.5p1, the NULL must not be given to qsort. */
242 qsort(table
, size
, sizeof(*table
), compare
);
244 for (i
= 0; i
< size
; i
++) {
245 display_entry(table
[i
], dircolor
);
250 smb_directory(int dir
, struct uri
*uri
)
253 unsigned char dircolor
[8] = "";
255 if (init_directory_listing(&buf
, uri
) != S_OK
) {
256 smb_error(-S_OUT_OF_MEM
);
259 fputs("text/html", header_out
);
262 fputs(buf
.source
, data_out
);
263 fputc('\n', data_out
);
265 if (get_opt_bool("document.browse.links.color_dirs", NULL
)) {
266 color_to_string(get_opt_color("document.colors.dirs", NULL
),
270 sort_and_display_entries(dir
, dircolor
);
271 fputs("</pre><hr/></body></html>\n", data_out
);
277 smb_auth(const char *srv
, const char *shr
, char *wg
, int wglen
, char *un
,
278 int unlen
, char *pw
, int pwlen
)
283 #define READ_SIZE 4096
286 do_smb(struct connection
*conn
)
288 struct uri
*uri
= conn
->uri
;
289 struct auth_entry
*auth
= find_auth(uri
);
290 struct string string
;
294 if ((uri
->userlen
&& uri
->passwordlen
) || !auth
) {
295 url
= get_uri_string(uri
, URI_BASE
);
297 unsigned char *uri_string
= get_uri_string(uri
, URI_HOST
| URI_PORT
| URI_DATA
);
299 if (!uri_string
|| !init_string(&string
)) {
300 smb_error(-S_OUT_OF_MEM
);
302 /* Must URI-encode the username and password to avoid
303 * ambiguity if they contain "/:@" characters.
304 * Libsmbclient then decodes them again, and the
305 * server gets them as they were in auth->user and
306 * auth->password, i.e. as the user typed them in the
307 * auth dialog. This implies that, if the username or
308 * password contains some characters or bytes that the
309 * user cannot directly type, then she cannot enter
310 * them. If that becomes an actual problem, it should
311 * be fixed in the auth dialog, e.g. by providing a
312 * hexadecimal input mode. */
313 add_to_string(&string
, "smb://");
314 encode_uri_string(&string
, auth
->user
, -1, 1);
315 add_char_to_string(&string
, ':');
316 encode_uri_string(&string
, auth
->password
, -1, 1);
317 add_char_to_string(&string
, '@');
318 add_to_string(&string
, uri_string
);
323 smb_error(-S_OUT_OF_MEM
);
325 if (smbc_init(smb_auth
, 0)) {
329 dir
= smbc_opendir(url
);
331 smb_directory(dir
, conn
->uri
);
333 const int errno_from_opendir
= errno
;
337 int file
= smbc_open(url
, O_RDONLY
, 0);
340 /* If we're opening the list of shares without
341 * proper authentication, then smbc_opendir
342 * fails with EACCES and smbc_open fails with
343 * ENOENT. In this case, return the EACCES so
344 * that the parent ELinks process will prompt
345 * for credentials. */
346 if (errno
== ENOENT
&& errno_from_opendir
== EACCES
)
347 errno
= errno_from_opendir
;
351 res
= smbc_fstat(file
, &sb
);
356 fprintf(header_out
, "%" OFF_PRINT_FORMAT
,
357 (off_print_T
) sb
.st_size
);
360 fdout
= fileno(data_out
);
361 while ((r
= smbc_read(file
, buf
, READ_SIZE
)) > 0) {
362 if (safe_write(fdout
, buf
, r
) <= 0)
372 /* Kill the current connection and ask for a username/password for the next
375 prompt_username_pw(struct connection
*conn
)
377 add_auth_entry(conn
->uri
, "Samba", NULL
, NULL
, 0);
378 abort_connection(conn
, S_OK
);
382 smb_got_error(struct socket
*socket
, struct read_buffer
*rb
)
384 int len
= rb
->length
;
385 struct connection
*conn
= socket
->conn
;
389 abort_connection(conn
, -errno
);
393 /* There should be free space in the buffer, because
394 * @alloc_read_buffer allocated several kibibytes, and the
395 * child process wrote only an integer and a newline to the
397 assert(rb
->freespace
>= 1);
399 abort_connection(conn
, S_INTERNAL
);
402 rb
->data
[len
] = '\0';
403 error
= atoi(rb
->data
);
404 kill_buffer_data(rb
, len
);
407 prompt_username_pw(conn
);
410 abort_connection(conn
, -error
);
416 smb_got_data(struct socket
*socket
, struct read_buffer
*rb
)
418 int len
= rb
->length
;
419 struct connection
*conn
= socket
->conn
;
422 abort_connection(conn
, -errno
);
427 abort_connection(conn
, S_OK
);
431 socket
->state
= SOCKET_END_ONCLOSE
;
432 conn
->received
+= len
;
433 if (add_fragment(conn
->cached
, conn
->from
, rb
->data
, len
) == 1)
436 kill_buffer_data(rb
, len
);
438 read_from_socket(socket
, rb
, S_TRANS
, smb_got_data
);
442 smb_got_header(struct socket
*socket
, struct read_buffer
*rb
)
444 struct connection
*conn
= socket
->conn
;
445 struct read_buffer
*buf
;
448 conn
->cached
= get_cache_entry(conn
->uri
);
450 /* Even though these are pipes rather than real
451 * sockets, call close_socket instead of close, to
452 * ensure that abort_connection won't try to close the
453 * file descriptors again. (Could we skip the calls
454 * and assume abort_connection will do them?) */
455 close_socket(socket
);
456 close_socket(conn
->data_socket
);
457 abort_connection(conn
, S_OUT_OF_MEM
);
460 socket
->state
= SOCKET_END_ONCLOSE
;
462 if (rb
->length
> 0) {
463 unsigned char *ctype
= memacpy(rb
->data
, rb
->length
);
465 if (ctype
&& *ctype
) {
466 if (!strcmp(ctype
, "text/x-error")) {
470 if (ctype
[0] >= '0' && ctype
[0] <= '9') {
472 conn
->est_length
= (off_t
)atoll(ctype
);
474 conn
->est_length
= (off_t
)atol(ctype
);
479 if (!conn
->est_length
) {
480 abort_connection(conn
, S_OK
);
484 else mem_free_set(&conn
->cached
->content_type
, ctype
);
491 buf
= alloc_read_buffer(conn
->data_socket
);
493 close_socket(socket
);
494 close_socket(conn
->data_socket
);
495 abort_connection(conn
, S_OUT_OF_MEM
);
499 mem_free_set(&conn
->cached
->content_type
, stracpy("text/html"));
500 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_error
);
502 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_data
);
507 close_all_fds_but_two(int header
, int data
)
514 if (!getrlimit(RLIMIT_NOFILE
, &lim
))
517 for (n
= 3; n
< max
; n
++) {
518 if (n
!= header
&& n
!= data
) close(n
);
525 smb_protocol_handler(struct connection
*conn
)
527 int smb_pipe
[2] = { -1, -1 };
528 int header_pipe
[2] = { -1, -1 };
531 if (c_pipe(smb_pipe
) || c_pipe(header_pipe
)) {
534 if (smb_pipe
[0] >= 0) close(smb_pipe
[0]);
535 if (smb_pipe
[1] >= 0) close(smb_pipe
[1]);
536 if (header_pipe
[0] >= 0) close(header_pipe
[0]);
537 if (header_pipe
[1] >= 0) close(header_pipe
[1]);
538 abort_connection(conn
, -s_errno
);
542 conn
->unrestartable
= 1;
543 find_auth(conn
->uri
); /* remember username and password */
551 close(header_pipe
[0]);
552 close(header_pipe
[1]);
553 retry_connection(conn
, -s_errno
);
558 dup2(open("/dev/null", O_RDONLY
), 0);
561 data_out
= fdopen(smb_pipe
[1], "w");
562 header_out
= fdopen(header_pipe
[1], "w");
564 if (!data_out
|| !header_out
) exit(1);
567 close(header_pipe
[0]);
569 /* There may be outgoing data in stdio buffers
570 * inherited from the parent process. The parent
571 * process is going to write this data, so the child
572 * process must not do that. Closing the file
573 * descriptors ensures this.
575 * FIXME: If something opens more files and gets the
576 * same file descriptors and does not close them
577 * before exit(), then stdio may attempt to write the
578 * buffers to the wrong files. This might happen for
579 * example if libsmbclient calls syslog(). */
581 close_all_fds_but_two(smb_pipe
[1], header_pipe
[1]);
585 struct read_buffer
*buf2
;
587 conn
->data_socket
->fd
= smb_pipe
[0];
588 conn
->socket
->fd
= header_pipe
[0];
589 set_nonblocking_fd(conn
->data_socket
->fd
);
590 set_nonblocking_fd(conn
->socket
->fd
);
592 close(header_pipe
[1]);
593 buf2
= alloc_read_buffer(conn
->socket
);
595 close_socket(conn
->data_socket
);
596 close_socket(conn
->socket
);
597 abort_connection(conn
, S_OUT_OF_MEM
);
600 read_from_socket(conn
->socket
, buf2
, S_CONN
, smb_got_header
);