1 /* SMB protocol implementation */
4 #define _GNU_SOURCE /* Needed for asprintf() */
12 #ifdef HAVE_LIBSMBCLIENT_H
13 #include <libsmbclient.h>
19 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
27 #include "cache/cache.h"
28 #include "config/options.h"
29 #include "intl/gettext/libintl.h"
30 #include "main/module.h"
31 #include "main/select.h"
32 #include "network/connection.h"
33 #include "network/socket.h"
34 #include "osdep/osdep.h"
35 #include "protocol/auth/auth.h"
36 #include "protocol/common.h"
37 #include "protocol/protocol.h"
38 #include "protocol/smb/smb.h"
39 #include "protocol/uri.h"
40 #include "util/conv.h"
41 #include "util/memory.h"
42 #include "util/snprintf.h"
43 #include "util/string.h"
45 /* These options are not used. */
46 struct option_info smb_options
[] = {
47 INIT_OPT_TREE("protocol", N_("SMB"),
49 N_("SAMBA specific options.")),
51 INIT_OPT_STRING("protocol.smb", N_("Credentials"),
53 N_("Credentials file passed to smbclient via -A option.")),
58 struct module smb_protocol_module
= struct_module(
59 /* name: */ N_("SMB"),
60 /* options: */ smb_options
,
62 /* submodules: */ NULL
,
71 fprintf(stderr
, "text/x-error");
72 printf("%d\n", error
);
77 compare(const void *a
, const void *b
)
79 const struct smbc_dirent
**da
= (const struct smbc_dirent
**)a
;
80 const struct smbc_dirent
**db
= (const struct smbc_dirent
**)b
;
81 int res
= (*da
)->smbc_type
- (*db
)->smbc_type
;
86 return strcmp((*da
)->name
, (*db
)->name
);
90 smb_add_link(struct string
*string
, struct smbc_dirent
*entry
,
91 unsigned char *text
, unsigned char dircolor
[])
93 add_to_string(string
, "<a href=\"");
94 add_to_string(string
, entry
->name
);
95 add_to_string(string
, "\">");
97 add_to_string(string
, "<font color=\"");
98 add_to_string(string
, dircolor
);
99 add_to_string(string
, "\"><b>");
101 add_to_string(string
, entry
->name
);
103 add_to_string(string
, "</b></font>");
105 add_to_string(string
, "</a>");
106 if (text
) add_to_string(string
, text
);
110 display_entry(struct smbc_dirent
*entry
, unsigned char dircolor
[])
112 static unsigned char zero
= '\0';
113 struct string string
;
115 if (!init_string(&string
)) return;
117 switch (entry
->smbc_type
) {
119 smb_add_link(&string
, entry
, " WORKGROUP ", dircolor
);
122 smb_add_link(&string
, entry
, " SERVER ", dircolor
);
123 if (entry
->comment
) add_to_string(&string
, entry
->comment
);
125 case SMBC_FILE_SHARE
:
126 smb_add_link(&string
, entry
, " FILE SHARE ", dircolor
);
127 if (entry
->comment
) add_to_string(&string
, entry
->comment
);
129 case SMBC_PRINTER_SHARE
:
130 add_to_string(&string
, entry
->name
);
131 add_to_string(&string
, " PRINTER ");
132 if (entry
->comment
) add_to_string(&string
, entry
->comment
);
134 case SMBC_COMMS_SHARE
:
135 add_to_string(&string
, entry
->name
);
136 add_to_string(&string
, " COMM");
139 add_to_string(&string
, entry
->name
);
140 add_to_string(&string
, " IPC");
143 smb_add_link(&string
, entry
, NULL
, dircolor
);
146 smb_add_link(&string
, entry
, " Link", &zero
);
149 smb_add_link(&string
, entry
, NULL
, &zero
);
156 done_string(&string
);
160 sort_and_display_entries(int dir
, unsigned char dircolor
[])
162 struct smbc_dirent
*fentry
, **table
= NULL
;
166 while ((fentry
= smbc_readdir(dir
))) {
167 struct smbc_dirent
**new_table
, *new_entry
;
168 int length
= fentry
->dirlen
;
170 if (!strcmp(fentry
->name
, "."))
173 new_entry
= mem_alloc(length
);
174 if (fentry
->comment
) {
175 char *comment
= mem_alloc(fentry
->commentlen
+ 1);
177 if (comment
) memcpy(comment
, fentry
->comment
, fentry
->commentlen
+ 1);
178 fentry
->comment
= comment
;
182 new_table
= mem_realloc(table
, (size
+ 1) * sizeof(*table
));
185 memcpy(new_entry
, fentry
, length
);
187 table
[size
] = new_entry
;
190 qsort(table
, size
, sizeof(*table
),
191 (int (*)(const void *, const void *)) compare
);
193 for (i
= 0; i
< size
; i
++) {
194 display_entry(table
[i
], dircolor
);
199 smb_directory(int dir
, struct uri
*uri
)
202 unsigned char dircolor
[8] = "";
204 if (init_directory_listing(&buf
, uri
) != S_OK
) {
205 smb_error(-S_OUT_OF_MEM
);
208 fprintf(stderr
, "text/html");
213 if (get_opt_bool("document.browse.links.color_dirs")) {
214 color_to_string(get_opt_color("document.colors.dirs"),
215 (unsigned char *) &dircolor
);
218 sort_and_display_entries(dir
, dircolor
);
219 puts("</pre><hr/></body></html>");
225 smb_auth(const char *srv
, const char *shr
, char *wg
, int wglen
, char *un
,
226 int unlen
, char *pw
, int pwlen
)
231 #define READ_SIZE 4096
234 do_smb(struct connection
*conn
)
236 struct uri
*uri
= conn
->uri
;
237 struct auth_entry
*auth
= find_auth(uri
);
238 struct string string
;
242 if ((uri
->userlen
&& uri
->passwordlen
) || !auth
|| !auth
->valid
) {
243 url
= get_uri_string(uri
, URI_BASE
);
245 unsigned char *uri_string
= get_uri_string(uri
, URI_HOST
| URI_PORT
| URI_DATA
);
247 if (!uri_string
|| !init_string(&string
)) {
248 smb_error(-S_OUT_OF_MEM
);
250 add_to_string(&string
, "smb://");
251 add_to_string(&string
, auth
->user
);
252 add_char_to_string(&string
, ':');
253 add_to_string(&string
, auth
->password
);
254 add_char_to_string(&string
, '@');
255 add_to_string(&string
, uri_string
);
260 smb_error(-S_OUT_OF_MEM
);
262 if (smbc_init(smb_auth
, 0)) {
265 dir
= smbc_opendir(url
);
267 smb_directory(dir
, conn
->uri
);
272 int file
= smbc_open(url
, O_RDONLY
, 0);
278 res
= smbc_fstat(file
, &sb
);
283 fprintf(stderr
, "%" OFF_T_FORMAT
, sb
.st_size
);
286 while ((r
= smbc_read(file
, buf
, READ_SIZE
)) > 0) {
287 if (safe_write(STDOUT_FILENO
, buf
, r
) <= 0)
297 /* Kill the current connection and ask for a username/password for the next
300 prompt_username_pw(struct connection
*conn
)
302 add_auth_entry(conn
->uri
, "Samba", NULL
, NULL
, 0);
303 abort_connection(conn
, S_OK
);
307 smb_got_error(struct socket
*socket
, struct read_buffer
*rb
)
309 int len
= rb
->length
;
310 struct connection
*conn
= socket
->conn
;
314 abort_connection(conn
, -errno
);
318 rb
->data
[len
] = '\0';
319 error
= atoi(rb
->data
);
320 kill_buffer_data(rb
, len
);
323 prompt_username_pw(conn
);
326 abort_connection(conn
, -error
);
332 smb_got_data(struct socket
*socket
, struct read_buffer
*rb
)
334 int len
= rb
->length
;
335 struct connection
*conn
= socket
->conn
;
338 abort_connection(conn
, -errno
);
343 abort_connection(conn
, S_OK
);
347 socket
->state
= SOCKET_END_ONCLOSE
;
348 conn
->received
+= len
;
349 if (add_fragment(conn
->cached
, conn
->from
, rb
->data
, len
) == 1)
352 kill_buffer_data(rb
, len
);
354 read_from_socket(socket
, rb
, S_TRANS
, smb_got_data
);
358 smb_got_header(struct socket
*socket
, struct read_buffer
*rb
)
360 struct connection
*conn
= socket
->conn
;
361 struct read_buffer
*buf
;
364 conn
->cached
= get_cache_entry(conn
->uri
);
367 close(conn
->data_socket
->fd
);
368 abort_connection(conn
, S_OUT_OF_MEM
);
371 socket
->state
= SOCKET_END_ONCLOSE
;
373 if (rb
->length
> 0) {
374 unsigned char *ctype
= memacpy(rb
->data
, rb
->length
);
376 if (ctype
&& *ctype
) {
377 if (!strcmp(ctype
, "text/x-error")) {
381 if (ctype
[0] >= '0' && ctype
[0] <= '9') {
383 conn
->est_length
= (off_t
)atoll(ctype
);
385 conn
->est_length
= (off_t
)atoi(ctype
);
390 if (!conn
->est_length
) {
391 abort_connection(conn
, S_OK
);
395 else mem_free_set(&conn
->cached
->content_type
, ctype
);
402 buf
= alloc_read_buffer(conn
->data_socket
);
405 close(conn
->data_socket
->fd
);
406 abort_connection(conn
, S_OUT_OF_MEM
);
410 mem_free_set(&conn
->cached
->content_type
, stracpy("text/html"));
411 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_error
);
413 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_data
);
418 smb_protocol_handler(struct connection
*conn
)
420 int smb_pipe
[2] = { -1, -1 };
421 int header_pipe
[2] = { -1, -1 };
424 if (c_pipe(smb_pipe
) || c_pipe(header_pipe
)) {
427 if (smb_pipe
[0] >= 0) close(smb_pipe
[0]);
428 if (smb_pipe
[1] >= 0) close(smb_pipe
[1]);
429 if (header_pipe
[0] >= 0) close(header_pipe
[0]);
430 if (header_pipe
[1] >= 0) close(header_pipe
[1]);
431 abort_connection(conn
, -s_errno
);
435 conn
->unrestartable
= 1;
443 close(header_pipe
[0]);
444 close(header_pipe
[1]);
445 retry_connection(conn
, -s_errno
);
450 dup2(smb_pipe
[1], 1);
451 dup2(open("/dev/null", O_RDONLY
), 0);
452 dup2(header_pipe
[1], 2);
454 close(header_pipe
[0]);
456 close_all_non_term_fd();
460 struct read_buffer
*buf2
;
462 conn
->data_socket
->fd
= smb_pipe
[0];
463 conn
->socket
->fd
= header_pipe
[0];
465 close(header_pipe
[1]);
466 buf2
= alloc_read_buffer(conn
->socket
);
469 close(header_pipe
[0]);
470 abort_connection(conn
, S_OUT_OF_MEM
);
473 read_from_socket(conn
->socket
, buf2
, S_CONN
, smb_got_header
);