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 display_entry(struct smbc_dirent
*entry
, unsigned char dircolor
[])
92 switch (entry
->smbc_type
) {
94 printf("<a href=\"%s\">", entry
->name
);
96 printf("<font color=\"%s\"><b>", dircolor
);
98 printf("%s", entry
->name
);
100 printf("</b></font>");
102 puts("</a> WORKGROUP");
105 printf("<a href=\"%s\">", entry
->name
);
107 printf("<font color=\"%s\"><b>", dircolor
);
109 printf("%s", entry
->name
);
111 printf("</b></font>");
113 printf("</a> SERVER ");
114 puts(entry
->comment
? entry
->comment
: "");
116 case SMBC_FILE_SHARE
:
117 printf("<a href=\"%s\">", entry
->name
);
119 printf("<font color=\"%s\"><b>", dircolor
);
121 printf("%s", entry
->name
);
123 printf("</b></font>");
125 printf("</a> FILE SHARE ");
126 puts(entry
->comment
? entry
->comment
: "");
128 case SMBC_PRINTER_SHARE
:
129 printf("%s PRINTER ", entry
->name
);
130 puts(entry
->comment
? entry
->comment
: "");
132 case SMBC_COMMS_SHARE
:
133 printf("%s COMM\n", entry
->name
);
136 printf("%s IPC\n", entry
->name
);
139 printf("<a href=\"%s\">", entry
->name
);
141 printf("<font color=\"%s\"><b>", dircolor
);
143 printf("%s", entry
->name
);
145 printf("</b></font>");
150 printf("<a href=\"%s\">%s</a> Link\n", entry
->name
, entry
->name
);
153 printf("<a href=\"%s\">%s</a>\n", entry
->name
, entry
->name
);
162 sort_and_display_entries(int dir
, unsigned char dircolor
[])
164 struct smbc_dirent
*fentry
, **table
= NULL
;
168 while ((fentry
= smbc_readdir(dir
))) {
169 struct smbc_dirent
**new_table
, *new_entry
;
170 int length
= fentry
->dirlen
;
172 if (!strcmp(fentry
->name
, "."))
175 new_entry
= mem_alloc(length
);
176 if (fentry
->comment
) {
177 char *comment
= mem_alloc(fentry
->commentlen
+ 1);
179 if (comment
) memcpy(comment
, fentry
->comment
, fentry
->commentlen
+ 1);
180 fentry
->comment
= comment
;
184 new_table
= mem_realloc(table
, (size
+ 1) * sizeof(*table
));
187 memcpy(new_entry
, fentry
, length
);
189 table
[size
] = new_entry
;
192 qsort(table
, size
, sizeof(*table
),
193 (int (*)(const void *, const void *)) compare
);
195 for (i
= 0; i
< size
; i
++) {
196 display_entry(table
[i
], dircolor
);
201 smb_directory(int dir
, struct uri
*uri
)
204 unsigned char dircolor
[8] = "";
206 if (init_directory_listing(&buf
, uri
) != S_OK
) {
207 smb_error(-S_OUT_OF_MEM
);
210 fprintf(stderr
, "text/html");
215 if (get_opt_bool("document.browse.links.color_dirs")) {
216 color_to_string(get_opt_color("document.colors.dirs"),
217 (unsigned char *) &dircolor
);
220 sort_and_display_entries(dir
, dircolor
);
221 puts("</pre><hr/></body></html>");
227 smb_auth(const char *srv
, const char *shr
, char *wg
, int wglen
, char *un
,
228 int unlen
, char *pw
, int pwlen
)
233 #define READ_SIZE 4096
236 do_smb(struct connection
*conn
)
238 struct uri
*uri
= conn
->uri
;
239 struct auth_entry
*auth
= find_auth(uri
);
240 struct string string
;
244 if ((uri
->userlen
&& uri
->passwordlen
) || !auth
|| !auth
->valid
) {
245 url
= get_uri_string(uri
, URI_BASE
);
247 unsigned char *uri_string
= get_uri_string(uri
, URI_HOST
| URI_PORT
| URI_DATA
);
249 if (!uri_string
|| !init_string(&string
)) {
250 smb_error(-S_OUT_OF_MEM
);
252 add_to_string(&string
, "smb://");
253 add_to_string(&string
, auth
->user
);
254 add_char_to_string(&string
, ':');
255 add_to_string(&string
, auth
->password
);
256 add_char_to_string(&string
, '@');
257 add_to_string(&string
, uri_string
);
262 smb_error(-S_OUT_OF_MEM
);
264 if (smbc_init(smb_auth
, 0)) {
267 dir
= smbc_opendir(url
);
269 smb_directory(dir
, conn
->uri
);
274 int file
= smbc_open(url
, O_RDONLY
, 0);
280 res
= smbc_fstat(file
, &sb
);
285 fprintf(stderr
, "%" OFF_T_FORMAT
, sb
.st_size
);
288 while ((r
= smbc_read(file
, buf
, READ_SIZE
)) > 0) {
289 if (safe_write(STDOUT_FILENO
, buf
, r
) <= 0)
299 /* Kill the current connection and ask for a username/password for the next
302 prompt_username_pw(struct connection
*conn
)
304 add_auth_entry(conn
->uri
, "Samba", NULL
, NULL
, 0);
305 abort_connection(conn
, S_OK
);
309 smb_got_error(struct socket
*socket
, struct read_buffer
*rb
)
311 int len
= rb
->length
;
312 struct connection
*conn
= socket
->conn
;
316 abort_connection(conn
, -errno
);
320 rb
->data
[len
] = '\0';
321 error
= atoi(rb
->data
);
322 kill_buffer_data(rb
, len
);
325 prompt_username_pw(conn
);
328 abort_connection(conn
, -error
);
334 smb_got_data(struct socket
*socket
, struct read_buffer
*rb
)
336 int len
= rb
->length
;
337 struct connection
*conn
= socket
->conn
;
340 abort_connection(conn
, -errno
);
345 abort_connection(conn
, S_OK
);
349 socket
->state
= SOCKET_END_ONCLOSE
;
350 conn
->received
+= len
;
351 if (add_fragment(conn
->cached
, conn
->from
, rb
->data
, len
) == 1)
354 kill_buffer_data(rb
, len
);
356 read_from_socket(socket
, rb
, S_TRANS
, smb_got_data
);
360 smb_got_header(struct socket
*socket
, struct read_buffer
*rb
)
362 struct connection
*conn
= socket
->conn
;
363 struct read_buffer
*buf
;
366 conn
->cached
= get_cache_entry(conn
->uri
);
369 close(conn
->data_socket
->fd
);
370 abort_connection(conn
, S_OUT_OF_MEM
);
373 socket
->state
= SOCKET_END_ONCLOSE
;
375 if (rb
->length
> 0) {
376 unsigned char *ctype
= memacpy(rb
->data
, rb
->length
);
378 if (ctype
&& *ctype
) {
379 if (!strcmp(ctype
, "text/x-error")) {
383 if (ctype
[0] >= '0' && ctype
[0] <= '9') {
385 conn
->est_length
= (off_t
)atoll(ctype
);
387 conn
->est_length
= (off_t
)atoi(ctype
);
391 else mem_free_set(&conn
->cached
->content_type
, ctype
);
398 buf
= alloc_read_buffer(conn
->data_socket
);
401 close(conn
->data_socket
->fd
);
402 abort_connection(conn
, S_OUT_OF_MEM
);
406 mem_free_set(&conn
->cached
->content_type
, stracpy("text/html"));
407 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_error
);
409 read_from_socket(conn
->data_socket
, buf
, S_CONN
, smb_got_data
);
414 smb_protocol_handler(struct connection
*conn
)
416 int smb_pipe
[2] = { -1, -1 };
417 int header_pipe
[2] = { -1, -1 };
420 if (c_pipe(smb_pipe
) || c_pipe(header_pipe
)) {
423 if (smb_pipe
[0] >= 0) close(smb_pipe
[0]);
424 if (smb_pipe
[1] >= 0) close(smb_pipe
[1]);
425 if (header_pipe
[0] >= 0) close(header_pipe
[0]);
426 if (header_pipe
[1] >= 0) close(header_pipe
[1]);
427 abort_connection(conn
, -s_errno
);
431 conn
->unrestartable
= 1;
439 close(header_pipe
[0]);
440 close(header_pipe
[1]);
441 retry_connection(conn
, -s_errno
);
446 dup2(smb_pipe
[1], 1);
447 dup2(open("/dev/null", O_RDONLY
), 0);
448 dup2(header_pipe
[1], 2);
450 close(header_pipe
[0]);
452 close_all_non_term_fd();
456 struct read_buffer
*buf2
;
458 conn
->data_socket
->fd
= smb_pipe
[0];
459 conn
->socket
->fd
= header_pipe
[0];
461 close(header_pipe
[1]);
462 buf2
= alloc_read_buffer(conn
->socket
);
465 close(header_pipe
[0]);
466 abort_connection(conn
, S_OUT_OF_MEM
);
469 read_from_socket(conn
->socket
, buf2
, S_CONN
, smb_got_header
);