Merge lp:~stefanor/ubuntu/lucid/samba/ntlm-auth-623342 into lp:ubuntu/lucid-proposed/samba

Proposed by Stefano Rivera on 2011-02-28
Status: Merged
Merge reported by: Benjamin Drung
Merged at revision: not available
Proposed branch: lp:~stefanor/ubuntu/lucid/samba/ntlm-auth-623342
Merge into: lp:ubuntu/lucid-proposed/samba
Diff against target: 19843 lines (+18478/-101)
96 files modified
.pc/applied-patches (+2/-0)
.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c (+247/-0)
.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c (+569/-0)
.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c (+690/-0)
.pc/security-CVE-2011-0719.patch/source3/client/client.c (+5022/-0)
.pc/security-CVE-2011-0719.patch/source3/client/dnsbrowse.c (+237/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/events.c (+304/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/packet.c (+267/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/readline.c (+201/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/select.c (+206/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/util_sock.c (+1989/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/wbclient.c (+715/-0)
.pc/security-CVE-2011-0719.patch/source3/libaddns/dnssock.c (+377/-0)
.pc/security-CVE-2011-0719.patch/source3/libads/cldap.c (+308/-0)
.pc/security-CVE-2011-0719.patch/source3/libsmb/nmblib.c (+1399/-0)
.pc/security-CVE-2011-0719.patch/source3/nmbd/nmbd_packets.c (+1967/-0)
.pc/security-CVE-2011-0719.patch/source3/utils/smbfilter.c (+295/-0)
.pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd.c (+1440/-0)
.pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c (+1477/-0)
debian/changelog (+18/-0)
debian/control (+1/-1)
debian/patches/ntlm-auth-lp623342.patch (+63/-0)
debian/patches/security-CVE-2011-0719.patch (+438/-0)
debian/patches/series (+2/-1)
debian/po/ar.po (+1/-1)
debian/po/ast.po (+1/-1)
debian/po/be.po (+1/-1)
debian/po/bg.po (+1/-1)
debian/po/bn.po (+1/-1)
debian/po/bs.po (+1/-1)
debian/po/ca.po (+3/-3)
debian/po/cs.po (+1/-1)
debian/po/da.po (+1/-1)
debian/po/de.po (+1/-1)
debian/po/dz.po (+1/-1)
debian/po/el.po (+1/-1)
debian/po/eo.po (+1/-1)
debian/po/es.po (+2/-3)
debian/po/et.po (+1/-1)
debian/po/eu.po (+1/-1)
debian/po/fi.po (+1/-1)
debian/po/fr.po (+1/-1)
debian/po/gl.po (+1/-1)
debian/po/gu.po (+1/-1)
debian/po/he.po (+1/-1)
debian/po/hu.po (+1/-1)
debian/po/id.po (+1/-1)
debian/po/it.po (+1/-1)
debian/po/ja.po (+1/-1)
debian/po/ka.po (+1/-1)
debian/po/km.po (+1/-1)
debian/po/ko.po (+1/-1)
debian/po/ku.po (+1/-1)
debian/po/lt.po (+3/-3)
debian/po/ml.po (+1/-1)
debian/po/mr.po (+4/-4)
debian/po/nb.po (+6/-6)
debian/po/ne.po (+1/-1)
debian/po/nl.po (+1/-1)
debian/po/nn.po (+5/-5)
debian/po/pl.po (+1/-1)
debian/po/pt.po (+1/-1)
debian/po/pt_BR.po (+1/-1)
debian/po/ro.po (+1/-1)
debian/po/ru.po (+3/-3)
debian/po/sk.po (+1/-1)
debian/po/sl.po (+1/-1)
debian/po/sq.po (+1/-1)
debian/po/sv.po (+1/-1)
debian/po/ta.po (+1/-1)
debian/po/th.po (+1/-1)
debian/po/tl.po (+1/-1)
debian/po/tr.po (+1/-1)
debian/po/vi.po (+11/-12)
debian/po/wo.po (+1/-1)
debian/po/zh_CN.po (+1/-1)
debian/po/zh_TW.po (+1/-1)
lib/tevent/tevent_select.c (+10/-0)
lib/tevent/tevent_standard.c (+5/-0)
nsswitch/wb_common.c (+17/-0)
source3/client/client.c (+3/-1)
source3/client/dnsbrowse.c (+11/-0)
source3/lib/events.c (+8/-0)
source3/lib/packet.c (+5/-0)
source3/lib/readline.c (+5/-0)
source3/lib/select.c (+12/-0)
source3/lib/util_sock.c (+9/-2)
source3/lib/wbclient.c (+8/-1)
source3/libaddns/dnssock.c (+5/-0)
source3/libads/cldap.c (+5/-0)
source3/libsmb/nmblib.c (+5/-0)
source3/nmbd/nmbd_packets.c (+22/-2)
source3/utils/smbfilter.c (+6/-2)
source3/winbindd/winbindd.c (+6/-0)
source3/winbindd/winbindd_cm.c (+13/-7)
source3/winbindd/winbindd_dual.c (+7/-0)
To merge this branch: bzr merge lp:~stefanor/ubuntu/lucid/samba/ntlm-auth-623342
Reviewer Review Type Date Requested Status
Ubuntu Development Team 2011-02-28 Pending
Review via email: mp+51560@code.launchpad.net

Description of the change

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.pc/applied-patches'
2--- .pc/applied-patches 2010-01-16 07:52:30 +0000
3+++ .pc/applied-patches 2011-03-02 20:47:51 +0000
4@@ -17,3 +17,5 @@
5 ubuntu-gecos-fix.patch
6 security-CVE-2010-3069.patch
7 spnego-auth-win7.patch
8+security-CVE-2011-0719.patch
9+ntlm-auth-lp623342.patch
10
11=== added directory '.pc/security-CVE-2011-0719.patch'
12=== added directory '.pc/security-CVE-2011-0719.patch/lib'
13=== added directory '.pc/security-CVE-2011-0719.patch/lib/tevent'
14=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c'
15--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c 1970-01-01 00:00:00 +0000
16+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c 2011-03-02 20:47:51 +0000
17@@ -0,0 +1,247 @@
18+/*
19+ Unix SMB/CIFS implementation.
20+ main select loop and event handling
21+ Copyright (C) Andrew Tridgell 2003-2005
22+ Copyright (C) Stefan Metzmacher 2005-2009
23+
24+ ** NOTE! The following LGPL license applies to the tevent
25+ ** library. This does NOT imply that all of Samba is released
26+ ** under the LGPL
27+
28+ This library is free software; you can redistribute it and/or
29+ modify it under the terms of the GNU Lesser General Public
30+ License as published by the Free Software Foundation; either
31+ version 3 of the License, or (at your option) any later version.
32+
33+ This library is distributed in the hope that it will be useful,
34+ but WITHOUT ANY WARRANTY; without even the implied warranty of
35+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36+ Lesser General Public License for more details.
37+
38+ You should have received a copy of the GNU Lesser General Public
39+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
40+*/
41+
42+#include "replace.h"
43+#include "system/filesys.h"
44+#include "system/select.h"
45+#include "tevent.h"
46+#include "tevent_util.h"
47+#include "tevent_internal.h"
48+
49+struct select_event_context {
50+ /* a pointer back to the generic event_context */
51+ struct tevent_context *ev;
52+
53+ /* the maximum file descriptor number in fd_events */
54+ int maxfd;
55+
56+ /* information for exiting from the event loop */
57+ int exit_code;
58+};
59+
60+/*
61+ create a select_event_context structure.
62+*/
63+static int select_event_context_init(struct tevent_context *ev)
64+{
65+ struct select_event_context *select_ev;
66+
67+ select_ev = talloc_zero(ev, struct select_event_context);
68+ if (!select_ev) return -1;
69+ select_ev->ev = ev;
70+
71+ ev->additional_data = select_ev;
72+ return 0;
73+}
74+
75+/*
76+ recalculate the maxfd
77+*/
78+static void calc_maxfd(struct select_event_context *select_ev)
79+{
80+ struct tevent_fd *fde;
81+
82+ select_ev->maxfd = 0;
83+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
84+ if (fde->fd > select_ev->maxfd) {
85+ select_ev->maxfd = fde->fd;
86+ }
87+ }
88+}
89+
90+
91+/* to mark the ev->maxfd invalid
92+ * this means we need to recalculate it
93+ */
94+#define EVENT_INVALID_MAXFD (-1)
95+
96+/*
97+ destroy an fd_event
98+*/
99+static int select_event_fd_destructor(struct tevent_fd *fde)
100+{
101+ struct tevent_context *ev = fde->event_ctx;
102+ struct select_event_context *select_ev = NULL;
103+
104+ if (ev) {
105+ select_ev = talloc_get_type(ev->additional_data,
106+ struct select_event_context);
107+
108+ if (select_ev->maxfd == fde->fd) {
109+ select_ev->maxfd = EVENT_INVALID_MAXFD;
110+ }
111+ }
112+
113+ return tevent_common_fd_destructor(fde);
114+}
115+
116+/*
117+ add a fd based event
118+ return NULL on failure (memory allocation error)
119+*/
120+static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
121+ int fd, uint16_t flags,
122+ tevent_fd_handler_t handler,
123+ void *private_data,
124+ const char *handler_name,
125+ const char *location)
126+{
127+ struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
128+ struct select_event_context);
129+ struct tevent_fd *fde;
130+
131+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
132+ handler, private_data,
133+ handler_name, location);
134+ if (!fde) return NULL;
135+
136+ if (fde->fd > select_ev->maxfd) {
137+ select_ev->maxfd = fde->fd;
138+ }
139+ talloc_set_destructor(fde, select_event_fd_destructor);
140+
141+ return fde;
142+}
143+
144+/*
145+ event loop handling using select()
146+*/
147+static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
148+{
149+ fd_set r_fds, w_fds;
150+ struct tevent_fd *fde;
151+ int selrtn;
152+
153+ /* we maybe need to recalculate the maxfd */
154+ if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
155+ calc_maxfd(select_ev);
156+ }
157+
158+ FD_ZERO(&r_fds);
159+ FD_ZERO(&w_fds);
160+
161+ /* setup any fd events */
162+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
163+ if (fde->flags & TEVENT_FD_READ) {
164+ FD_SET(fde->fd, &r_fds);
165+ }
166+ if (fde->flags & TEVENT_FD_WRITE) {
167+ FD_SET(fde->fd, &w_fds);
168+ }
169+ }
170+
171+ if (select_ev->ev->signal_events &&
172+ tevent_common_check_signal(select_ev->ev)) {
173+ return 0;
174+ }
175+
176+ selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
177+
178+ if (selrtn == -1 && errno == EINTR &&
179+ select_ev->ev->signal_events) {
180+ tevent_common_check_signal(select_ev->ev);
181+ return 0;
182+ }
183+
184+ if (selrtn == -1 && errno == EBADF) {
185+ /* the socket is dead! this should never
186+ happen as the socket should have first been
187+ made readable and that should have removed
188+ the event, so this must be a bug. This is a
189+ fatal error. */
190+ tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
191+ "ERROR: EBADF on select_event_loop_once\n");
192+ select_ev->exit_code = EBADF;
193+ return -1;
194+ }
195+
196+ if (selrtn == 0 && tvalp) {
197+ /* we don't care about a possible delay here */
198+ tevent_common_loop_timer_delay(select_ev->ev);
199+ return 0;
200+ }
201+
202+ if (selrtn > 0) {
203+ /* at least one file descriptor is ready - check
204+ which ones and call the handler, being careful to allow
205+ the handler to remove itself when called */
206+ for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
207+ uint16_t flags = 0;
208+
209+ if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
210+ if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
211+ if (flags) {
212+ fde->handler(select_ev->ev, fde, flags, fde->private_data);
213+ break;
214+ }
215+ }
216+ }
217+
218+ return 0;
219+}
220+
221+/*
222+ do a single event loop using the events defined in ev
223+*/
224+static int select_event_loop_once(struct tevent_context *ev, const char *location)
225+{
226+ struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
227+ struct select_event_context);
228+ struct timeval tval;
229+
230+ if (ev->signal_events &&
231+ tevent_common_check_signal(ev)) {
232+ return 0;
233+ }
234+
235+ if (ev->immediate_events &&
236+ tevent_common_loop_immediate(ev)) {
237+ return 0;
238+ }
239+
240+ tval = tevent_common_loop_timer_delay(ev);
241+ if (tevent_timeval_is_zero(&tval)) {
242+ return 0;
243+ }
244+
245+ return select_event_loop_select(select_ev, &tval);
246+}
247+
248+static const struct tevent_ops select_event_ops = {
249+ .context_init = select_event_context_init,
250+ .add_fd = select_event_add_fd,
251+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
252+ .get_fd_flags = tevent_common_fd_get_flags,
253+ .set_fd_flags = tevent_common_fd_set_flags,
254+ .add_timer = tevent_common_add_timer,
255+ .schedule_immediate = tevent_common_schedule_immediate,
256+ .add_signal = tevent_common_add_signal,
257+ .loop_once = select_event_loop_once,
258+ .loop_wait = tevent_common_loop_wait,
259+};
260+
261+bool tevent_select_init(void)
262+{
263+ return tevent_register_backend("select", &select_event_ops);
264+}
265
266=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c'
267--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c 1970-01-01 00:00:00 +0000
268+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c 2011-03-02 20:47:51 +0000
269@@ -0,0 +1,569 @@
270+/*
271+ Unix SMB/CIFS implementation.
272+ main select loop and event handling
273+ Copyright (C) Andrew Tridgell 2003-2005
274+ Copyright (C) Stefan Metzmacher 2005-2009
275+
276+ ** NOTE! The following LGPL license applies to the tevent
277+ ** library. This does NOT imply that all of Samba is released
278+ ** under the LGPL
279+
280+ This library is free software; you can redistribute it and/or
281+ modify it under the terms of the GNU Lesser General Public
282+ License as published by the Free Software Foundation; either
283+ version 3 of the License, or (at your option) any later version.
284+
285+ This library is distributed in the hope that it will be useful,
286+ but WITHOUT ANY WARRANTY; without even the implied warranty of
287+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
288+ Lesser General Public License for more details.
289+
290+ You should have received a copy of the GNU Lesser General Public
291+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
292+*/
293+
294+/*
295+ This is SAMBA's default event loop code
296+
297+ - we try to use epoll if configure detected support for it
298+ otherwise we use select()
299+ - if epoll is broken on the system or the kernel doesn't support it
300+ at runtime we fallback to select()
301+*/
302+
303+#include "replace.h"
304+#include "system/filesys.h"
305+#include "system/select.h"
306+#include "tevent.h"
307+#include "tevent_util.h"
308+#include "tevent_internal.h"
309+
310+struct std_event_context {
311+ /* a pointer back to the generic event_context */
312+ struct tevent_context *ev;
313+
314+ /* the maximum file descriptor number in fd_events */
315+ int maxfd;
316+
317+ /* information for exiting from the event loop */
318+ int exit_code;
319+
320+ /* when using epoll this is the handle from epoll_create */
321+ int epoll_fd;
322+
323+ /* our pid at the time the epoll_fd was created */
324+ pid_t pid;
325+};
326+
327+/* use epoll if it is available */
328+#if HAVE_EPOLL
329+/*
330+ called when a epoll call fails, and we should fallback
331+ to using select
332+*/
333+static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
334+{
335+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
336+ "%s (%s) - falling back to select()\n",
337+ reason, strerror(errno));
338+ close(std_ev->epoll_fd);
339+ std_ev->epoll_fd = -1;
340+ talloc_set_destructor(std_ev, NULL);
341+}
342+
343+/*
344+ map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
345+*/
346+static uint32_t epoll_map_flags(uint16_t flags)
347+{
348+ uint32_t ret = 0;
349+ if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
350+ if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
351+ return ret;
352+}
353+
354+/*
355+ free the epoll fd
356+*/
357+static int epoll_ctx_destructor(struct std_event_context *std_ev)
358+{
359+ if (std_ev->epoll_fd != -1) {
360+ close(std_ev->epoll_fd);
361+ }
362+ std_ev->epoll_fd = -1;
363+ return 0;
364+}
365+
366+/*
367+ init the epoll fd
368+*/
369+static void epoll_init_ctx(struct std_event_context *std_ev)
370+{
371+ std_ev->epoll_fd = epoll_create(64);
372+ std_ev->pid = getpid();
373+ talloc_set_destructor(std_ev, epoll_ctx_destructor);
374+}
375+
376+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
377+
378+/*
379+ reopen the epoll handle when our pid changes
380+ see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
381+ demonstration of why this is needed
382+ */
383+static void epoll_check_reopen(struct std_event_context *std_ev)
384+{
385+ struct tevent_fd *fde;
386+
387+ if (std_ev->pid == getpid()) {
388+ return;
389+ }
390+
391+ close(std_ev->epoll_fd);
392+ std_ev->epoll_fd = epoll_create(64);
393+ if (std_ev->epoll_fd == -1) {
394+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
395+ "Failed to recreate epoll handle after fork\n");
396+ return;
397+ }
398+ std_ev->pid = getpid();
399+ for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
400+ epoll_add_event(std_ev, fde);
401+ }
402+}
403+
404+#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
405+#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
406+#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
407+
408+/*
409+ add the epoll event to the given fd_event
410+*/
411+static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
412+{
413+ struct epoll_event event;
414+ if (std_ev->epoll_fd == -1) return;
415+
416+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
417+
418+ /* if we don't want events yet, don't add an epoll_event */
419+ if (fde->flags == 0) return;
420+
421+ ZERO_STRUCT(event);
422+ event.events = epoll_map_flags(fde->flags);
423+ event.data.ptr = fde;
424+ if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
425+ epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
426+ }
427+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
428+
429+ /* only if we want to read we want to tell the event handler about errors */
430+ if (fde->flags & TEVENT_FD_READ) {
431+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
432+ }
433+}
434+
435+/*
436+ delete the epoll event for given fd_event
437+*/
438+static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
439+{
440+ struct epoll_event event;
441+ if (std_ev->epoll_fd == -1) return;
442+
443+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
444+
445+ /* if there's no epoll_event, we don't need to delete it */
446+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
447+
448+ ZERO_STRUCT(event);
449+ event.events = epoll_map_flags(fde->flags);
450+ event.data.ptr = fde;
451+ epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
452+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
453+}
454+
455+/*
456+ change the epoll event to the given fd_event
457+*/
458+static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
459+{
460+ struct epoll_event event;
461+ if (std_ev->epoll_fd == -1) return;
462+
463+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
464+
465+ ZERO_STRUCT(event);
466+ event.events = epoll_map_flags(fde->flags);
467+ event.data.ptr = fde;
468+ if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
469+ epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
470+ }
471+
472+ /* only if we want to read we want to tell the event handler about errors */
473+ if (fde->flags & TEVENT_FD_READ) {
474+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
475+ }
476+}
477+
478+static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
479+{
480+ bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
481+ bool want_read = (fde->flags & TEVENT_FD_READ);
482+ bool want_write= (fde->flags & TEVENT_FD_WRITE);
483+
484+ if (std_ev->epoll_fd == -1) return;
485+
486+ fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
487+
488+ /* there's already an event */
489+ if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
490+ if (want_read || (want_write && !got_error)) {
491+ epoll_mod_event(std_ev, fde);
492+ return;
493+ }
494+ /*
495+ * if we want to match the select behavior, we need to remove the epoll_event
496+ * when the caller isn't interested in events.
497+ *
498+ * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
499+ */
500+ epoll_del_event(std_ev, fde);
501+ return;
502+ }
503+
504+ /* there's no epoll_event attached to the fde */
505+ if (want_read || (want_write && !got_error)) {
506+ epoll_add_event(std_ev, fde);
507+ return;
508+ }
509+}
510+
511+/*
512+ event loop handling using epoll
513+*/
514+static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
515+{
516+ int ret, i;
517+#define MAXEVENTS 1
518+ struct epoll_event events[MAXEVENTS];
519+ int timeout = -1;
520+
521+ if (std_ev->epoll_fd == -1) return -1;
522+
523+ if (tvalp) {
524+ /* it's better to trigger timed events a bit later than to early */
525+ timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
526+ }
527+
528+ if (std_ev->ev->signal_events &&
529+ tevent_common_check_signal(std_ev->ev)) {
530+ return 0;
531+ }
532+
533+ ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
534+
535+ if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
536+ if (tevent_common_check_signal(std_ev->ev)) {
537+ return 0;
538+ }
539+ }
540+
541+ if (ret == -1 && errno != EINTR) {
542+ epoll_fallback_to_select(std_ev, "epoll_wait() failed");
543+ return -1;
544+ }
545+
546+ if (ret == 0 && tvalp) {
547+ /* we don't care about a possible delay here */
548+ tevent_common_loop_timer_delay(std_ev->ev);
549+ return 0;
550+ }
551+
552+ for (i=0;i<ret;i++) {
553+ struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
554+ struct tevent_fd);
555+ uint16_t flags = 0;
556+
557+ if (fde == NULL) {
558+ epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
559+ return -1;
560+ }
561+ if (events[i].events & (EPOLLHUP|EPOLLERR)) {
562+ fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
563+ /*
564+ * if we only wait for TEVENT_FD_WRITE, we should not tell the
565+ * event handler about it, and remove the epoll_event,
566+ * as we only report errors when waiting for read events,
567+ * to match the select() behavior
568+ */
569+ if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
570+ epoll_del_event(std_ev, fde);
571+ continue;
572+ }
573+ flags |= TEVENT_FD_READ;
574+ }
575+ if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
576+ if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
577+ if (flags) {
578+ fde->handler(std_ev->ev, fde, flags, fde->private_data);
579+ break;
580+ }
581+ }
582+
583+ return 0;
584+}
585+#else
586+#define epoll_init_ctx(std_ev)
587+#define epoll_add_event(std_ev,fde)
588+#define epoll_del_event(std_ev,fde)
589+#define epoll_change_event(std_ev,fde)
590+#define epoll_event_loop(std_ev,tvalp) (-1)
591+#define epoll_check_reopen(std_ev)
592+#endif
593+
594+/*
595+ create a std_event_context structure.
596+*/
597+static int std_event_context_init(struct tevent_context *ev)
598+{
599+ struct std_event_context *std_ev;
600+
601+ std_ev = talloc_zero(ev, struct std_event_context);
602+ if (!std_ev) return -1;
603+ std_ev->ev = ev;
604+ std_ev->epoll_fd = -1;
605+
606+ epoll_init_ctx(std_ev);
607+
608+ ev->additional_data = std_ev;
609+ return 0;
610+}
611+
612+/*
613+ recalculate the maxfd
614+*/
615+static void calc_maxfd(struct std_event_context *std_ev)
616+{
617+ struct tevent_fd *fde;
618+
619+ std_ev->maxfd = 0;
620+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
621+ if (fde->fd > std_ev->maxfd) {
622+ std_ev->maxfd = fde->fd;
623+ }
624+ }
625+}
626+
627+
628+/* to mark the ev->maxfd invalid
629+ * this means we need to recalculate it
630+ */
631+#define EVENT_INVALID_MAXFD (-1)
632+
633+/*
634+ destroy an fd_event
635+*/
636+static int std_event_fd_destructor(struct tevent_fd *fde)
637+{
638+ struct tevent_context *ev = fde->event_ctx;
639+ struct std_event_context *std_ev = NULL;
640+
641+ if (ev) {
642+ std_ev = talloc_get_type(ev->additional_data,
643+ struct std_event_context);
644+
645+ epoll_check_reopen(std_ev);
646+
647+ if (std_ev->maxfd == fde->fd) {
648+ std_ev->maxfd = EVENT_INVALID_MAXFD;
649+ }
650+
651+ epoll_del_event(std_ev, fde);
652+ }
653+
654+ return tevent_common_fd_destructor(fde);
655+}
656+
657+/*
658+ add a fd based event
659+ return NULL on failure (memory allocation error)
660+*/
661+static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
662+ int fd, uint16_t flags,
663+ tevent_fd_handler_t handler,
664+ void *private_data,
665+ const char *handler_name,
666+ const char *location)
667+{
668+ struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
669+ struct std_event_context);
670+ struct tevent_fd *fde;
671+
672+ epoll_check_reopen(std_ev);
673+
674+ fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
675+ handler, private_data,
676+ handler_name, location);
677+ if (!fde) return NULL;
678+
679+ if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
680+ && (fde->fd > std_ev->maxfd)) {
681+ std_ev->maxfd = fde->fd;
682+ }
683+ talloc_set_destructor(fde, std_event_fd_destructor);
684+
685+ epoll_add_event(std_ev, fde);
686+
687+ return fde;
688+}
689+
690+/*
691+ set the fd event flags
692+*/
693+static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
694+{
695+ struct tevent_context *ev;
696+ struct std_event_context *std_ev;
697+
698+ if (fde->flags == flags) return;
699+
700+ ev = fde->event_ctx;
701+ std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
702+
703+ fde->flags = flags;
704+
705+ epoll_check_reopen(std_ev);
706+
707+ epoll_change_event(std_ev, fde);
708+}
709+
710+/*
711+ event loop handling using select()
712+*/
713+static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
714+{
715+ fd_set r_fds, w_fds;
716+ struct tevent_fd *fde;
717+ int selrtn;
718+
719+ /* we maybe need to recalculate the maxfd */
720+ if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
721+ calc_maxfd(std_ev);
722+ }
723+
724+ FD_ZERO(&r_fds);
725+ FD_ZERO(&w_fds);
726+
727+ /* setup any fd events */
728+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
729+ if (fde->flags & TEVENT_FD_READ) {
730+ FD_SET(fde->fd, &r_fds);
731+ }
732+ if (fde->flags & TEVENT_FD_WRITE) {
733+ FD_SET(fde->fd, &w_fds);
734+ }
735+ }
736+
737+ if (std_ev->ev->signal_events &&
738+ tevent_common_check_signal(std_ev->ev)) {
739+ return 0;
740+ }
741+
742+ selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
743+
744+ if (selrtn == -1 && errno == EINTR &&
745+ std_ev->ev->signal_events) {
746+ tevent_common_check_signal(std_ev->ev);
747+ return 0;
748+ }
749+
750+ if (selrtn == -1 && errno == EBADF) {
751+ /* the socket is dead! this should never
752+ happen as the socket should have first been
753+ made readable and that should have removed
754+ the event, so this must be a bug. This is a
755+ fatal error. */
756+ tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
757+ "ERROR: EBADF on std_event_loop_once\n");
758+ std_ev->exit_code = EBADF;
759+ return -1;
760+ }
761+
762+ if (selrtn == 0 && tvalp) {
763+ /* we don't care about a possible delay here */
764+ tevent_common_loop_timer_delay(std_ev->ev);
765+ return 0;
766+ }
767+
768+ if (selrtn > 0) {
769+ /* at least one file descriptor is ready - check
770+ which ones and call the handler, being careful to allow
771+ the handler to remove itself when called */
772+ for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
773+ uint16_t flags = 0;
774+
775+ if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
776+ if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
777+ if (flags) {
778+ fde->handler(std_ev->ev, fde, flags, fde->private_data);
779+ break;
780+ }
781+ }
782+ }
783+
784+ return 0;
785+}
786+
787+/*
788+ do a single event loop using the events defined in ev
789+*/
790+static int std_event_loop_once(struct tevent_context *ev, const char *location)
791+{
792+ struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
793+ struct std_event_context);
794+ struct timeval tval;
795+
796+ if (ev->signal_events &&
797+ tevent_common_check_signal(ev)) {
798+ return 0;
799+ }
800+
801+ if (ev->immediate_events &&
802+ tevent_common_loop_immediate(ev)) {
803+ return 0;
804+ }
805+
806+ tval = tevent_common_loop_timer_delay(ev);
807+ if (tevent_timeval_is_zero(&tval)) {
808+ return 0;
809+ }
810+
811+ epoll_check_reopen(std_ev);
812+
813+ if (epoll_event_loop(std_ev, &tval) == 0) {
814+ return 0;
815+ }
816+
817+ return std_event_loop_select(std_ev, &tval);
818+}
819+
820+static const struct tevent_ops std_event_ops = {
821+ .context_init = std_event_context_init,
822+ .add_fd = std_event_add_fd,
823+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
824+ .get_fd_flags = tevent_common_fd_get_flags,
825+ .set_fd_flags = std_event_set_fd_flags,
826+ .add_timer = tevent_common_add_timer,
827+ .schedule_immediate = tevent_common_schedule_immediate,
828+ .add_signal = tevent_common_add_signal,
829+ .loop_once = std_event_loop_once,
830+ .loop_wait = tevent_common_loop_wait,
831+};
832+
833+
834+bool tevent_standard_init(void)
835+{
836+ return tevent_register_backend("standard", &std_event_ops);
837+}
838+
839
840=== added directory '.pc/security-CVE-2011-0719.patch/nsswitch'
841=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c'
842--- .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 1970-01-01 00:00:00 +0000
843+++ .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 2011-03-02 20:47:51 +0000
844@@ -0,0 +1,690 @@
845+/*
846+ Unix SMB/CIFS implementation.
847+
848+ winbind client common code
849+
850+ Copyright (C) Tim Potter 2000
851+ Copyright (C) Andrew Tridgell 2000
852+ Copyright (C) Andrew Bartlett 2002
853+
854+
855+ This library is free software; you can redistribute it and/or
856+ modify it under the terms of the GNU Lesser General Public
857+ License as published by the Free Software Foundation; either
858+ version 3 of the License, or (at your option) any later version.
859+
860+ This library is distributed in the hope that it will be useful,
861+ but WITHOUT ANY WARRANTY; without even the implied warranty of
862+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
863+ Library General Public License for more details.
864+
865+ You should have received a copy of the GNU Lesser General Public License
866+ along with this program. If not, see <http://www.gnu.org/licenses/>.
867+*/
868+
869+#include "winbind_client.h"
870+
871+/* Global variables. These are effectively the client state information */
872+
873+int winbindd_fd = -1; /* fd for winbindd socket */
874+static int is_privileged = 0;
875+
876+/* Free a response structure */
877+
878+void winbindd_free_response(struct winbindd_response *response)
879+{
880+ /* Free any allocated extra_data */
881+
882+ if (response)
883+ SAFE_FREE(response->extra_data.data);
884+}
885+
886+/* Initialise a request structure */
887+
888+void winbindd_init_request(struct winbindd_request *request, int request_type)
889+{
890+ request->length = sizeof(struct winbindd_request);
891+
892+ request->cmd = (enum winbindd_cmd)request_type;
893+ request->pid = getpid();
894+
895+}
896+
897+/* Initialise a response structure */
898+
899+static void init_response(struct winbindd_response *response)
900+{
901+ /* Initialise return value */
902+
903+ response->result = WINBINDD_ERROR;
904+}
905+
906+/* Close established socket */
907+
908+void winbind_close_sock(void)
909+{
910+ if (winbindd_fd != -1) {
911+ close(winbindd_fd);
912+ winbindd_fd = -1;
913+ }
914+}
915+
916+#define CONNECT_TIMEOUT 30
917+
918+/* Make sure socket handle isn't stdin, stdout or stderr */
919+#define RECURSION_LIMIT 3
920+
921+static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
922+{
923+ int new_fd;
924+ if (fd >= 0 && fd <= 2) {
925+#ifdef F_DUPFD
926+ if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
927+ return -1;
928+ }
929+ /* Paranoia */
930+ if (new_fd < 3) {
931+ close(new_fd);
932+ return -1;
933+ }
934+ close(fd);
935+ return new_fd;
936+#else
937+ if (limit <= 0)
938+ return -1;
939+
940+ new_fd = dup(fd);
941+ if (new_fd == -1)
942+ return -1;
943+
944+ /* use the program stack to hold our list of FDs to close */
945+ new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
946+ close(fd);
947+ return new_fd;
948+#endif
949+ }
950+ return fd;
951+}
952+
953+/****************************************************************************
954+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
955+ else
956+ if SYSV use O_NDELAY
957+ if BSD use FNDELAY
958+ Set close on exec also.
959+****************************************************************************/
960+
961+static int make_safe_fd(int fd)
962+{
963+ int result, flags;
964+ int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
965+ if (new_fd == -1) {
966+ close(fd);
967+ return -1;
968+ }
969+
970+ /* Socket should be nonblocking. */
971+#ifdef O_NONBLOCK
972+#define FLAG_TO_SET O_NONBLOCK
973+#else
974+#ifdef SYSV
975+#define FLAG_TO_SET O_NDELAY
976+#else /* BSD */
977+#define FLAG_TO_SET FNDELAY
978+#endif
979+#endif
980+
981+ if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
982+ close(new_fd);
983+ return -1;
984+ }
985+
986+ flags |= FLAG_TO_SET;
987+ if (fcntl(new_fd, F_SETFL, flags) == -1) {
988+ close(new_fd);
989+ return -1;
990+ }
991+
992+#undef FLAG_TO_SET
993+
994+ /* Socket should be closed on exec() */
995+#ifdef FD_CLOEXEC
996+ result = flags = fcntl(new_fd, F_GETFD, 0);
997+ if (flags >= 0) {
998+ flags |= FD_CLOEXEC;
999+ result = fcntl( new_fd, F_SETFD, flags );
1000+ }
1001+ if (result < 0) {
1002+ close(new_fd);
1003+ return -1;
1004+ }
1005+#endif
1006+ return new_fd;
1007+}
1008+
1009+/* Connect to winbindd socket */
1010+
1011+static int winbind_named_pipe_sock(const char *dir)
1012+{
1013+ struct sockaddr_un sunaddr;
1014+ struct stat st;
1015+ char *path = NULL;
1016+ int fd;
1017+ int wait_time;
1018+ int slept;
1019+
1020+ /* Check permissions on unix socket directory */
1021+
1022+ if (lstat(dir, &st) == -1) {
1023+ errno = ENOENT;
1024+ return -1;
1025+ }
1026+
1027+ if (!S_ISDIR(st.st_mode) ||
1028+ (st.st_uid != 0 && st.st_uid != geteuid())) {
1029+ errno = ENOENT;
1030+ return -1;
1031+ }
1032+
1033+ /* Connect to socket */
1034+
1035+ if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
1036+ return -1;
1037+ }
1038+
1039+ ZERO_STRUCT(sunaddr);
1040+ sunaddr.sun_family = AF_UNIX;
1041+ strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
1042+
1043+ /* If socket file doesn't exist, don't bother trying to connect
1044+ with retry. This is an attempt to make the system usable when
1045+ the winbindd daemon is not running. */
1046+
1047+ if (lstat(path, &st) == -1) {
1048+ errno = ENOENT;
1049+ SAFE_FREE(path);
1050+ return -1;
1051+ }
1052+
1053+ SAFE_FREE(path);
1054+ /* Check permissions on unix socket file */
1055+
1056+ if (!S_ISSOCK(st.st_mode) ||
1057+ (st.st_uid != 0 && st.st_uid != geteuid())) {
1058+ errno = ENOENT;
1059+ return -1;
1060+ }
1061+
1062+ /* Connect to socket */
1063+
1064+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
1065+ return -1;
1066+ }
1067+
1068+ /* Set socket non-blocking and close on exec. */
1069+
1070+ if ((fd = make_safe_fd( fd)) == -1) {
1071+ return fd;
1072+ }
1073+
1074+ for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
1075+ wait_time += slept) {
1076+ struct timeval tv;
1077+ fd_set w_fds;
1078+ int ret;
1079+ int connect_errno = 0;
1080+ socklen_t errnosize;
1081+
1082+ if (wait_time >= CONNECT_TIMEOUT)
1083+ goto error_out;
1084+
1085+ switch (errno) {
1086+ case EINPROGRESS:
1087+ FD_ZERO(&w_fds);
1088+ FD_SET(fd, &w_fds);
1089+ tv.tv_sec = CONNECT_TIMEOUT - wait_time;
1090+ tv.tv_usec = 0;
1091+
1092+ ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
1093+
1094+ if (ret > 0) {
1095+ errnosize = sizeof(connect_errno);
1096+
1097+ ret = getsockopt(fd, SOL_SOCKET,
1098+ SO_ERROR, &connect_errno, &errnosize);
1099+
1100+ if (ret >= 0 && connect_errno == 0) {
1101+ /* Connect succeed */
1102+ goto out;
1103+ }
1104+ }
1105+
1106+ slept = CONNECT_TIMEOUT;
1107+ break;
1108+ case EAGAIN:
1109+ slept = rand() % 3 + 1;
1110+ sleep(slept);
1111+ break;
1112+ default:
1113+ goto error_out;
1114+ }
1115+
1116+ }
1117+
1118+ out:
1119+
1120+ return fd;
1121+
1122+ error_out:
1123+
1124+ close(fd);
1125+ return -1;
1126+}
1127+
1128+static const char *winbindd_socket_dir(void)
1129+{
1130+#ifdef SOCKET_WRAPPER
1131+ const char *env_dir;
1132+
1133+ env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
1134+ if (env_dir) {
1135+ return env_dir;
1136+ }
1137+#endif
1138+
1139+ return WINBINDD_SOCKET_DIR;
1140+}
1141+
1142+/* Connect to winbindd socket */
1143+
1144+static int winbind_open_pipe_sock(int recursing, int need_priv)
1145+{
1146+#ifdef HAVE_UNIXSOCKET
1147+ static pid_t our_pid;
1148+ struct winbindd_request request;
1149+ struct winbindd_response response;
1150+ ZERO_STRUCT(request);
1151+ ZERO_STRUCT(response);
1152+
1153+ if (our_pid != getpid()) {
1154+ winbind_close_sock();
1155+ our_pid = getpid();
1156+ }
1157+
1158+ if ((need_priv != 0) && (is_privileged == 0)) {
1159+ winbind_close_sock();
1160+ }
1161+
1162+ if (winbindd_fd != -1) {
1163+ return winbindd_fd;
1164+ }
1165+
1166+ if (recursing) {
1167+ return -1;
1168+ }
1169+
1170+ if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
1171+ return -1;
1172+ }
1173+
1174+ is_privileged = 0;
1175+
1176+ /* version-check the socket */
1177+
1178+ request.wb_flags = WBFLAG_RECURSE;
1179+ if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
1180+ winbind_close_sock();
1181+ return -1;
1182+ }
1183+
1184+ /* try and get priv pipe */
1185+
1186+ request.wb_flags = WBFLAG_RECURSE;
1187+ if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
1188+ int fd;
1189+ if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
1190+ close(winbindd_fd);
1191+ winbindd_fd = fd;
1192+ is_privileged = 1;
1193+ }
1194+ }
1195+
1196+ if ((need_priv != 0) && (is_privileged == 0)) {
1197+ return -1;
1198+ }
1199+
1200+ SAFE_FREE(response.extra_data.data);
1201+
1202+ return winbindd_fd;
1203+#else
1204+ return -1;
1205+#endif /* HAVE_UNIXSOCKET */
1206+}
1207+
1208+/* Write data to winbindd socket */
1209+
1210+int winbind_write_sock(void *buffer, int count, int recursing, int need_priv)
1211+{
1212+ int result, nwritten;
1213+
1214+ /* Open connection to winbind daemon */
1215+
1216+ restart:
1217+
1218+ if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
1219+ errno = ENOENT;
1220+ return -1;
1221+ }
1222+
1223+ /* Write data to socket */
1224+
1225+ nwritten = 0;
1226+
1227+ while(nwritten < count) {
1228+ struct timeval tv;
1229+ fd_set r_fds;
1230+
1231+ /* Catch pipe close on other end by checking if a read()
1232+ call would not block by calling select(). */
1233+
1234+ FD_ZERO(&r_fds);
1235+ FD_SET(winbindd_fd, &r_fds);
1236+ ZERO_STRUCT(tv);
1237+
1238+ if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
1239+ winbind_close_sock();
1240+ return -1; /* Select error */
1241+ }
1242+
1243+ /* Write should be OK if fd not available for reading */
1244+
1245+ if (!FD_ISSET(winbindd_fd, &r_fds)) {
1246+
1247+ /* Do the write */
1248+
1249+ result = write(winbindd_fd,
1250+ (char *)buffer + nwritten,
1251+ count - nwritten);
1252+
1253+ if ((result == -1) || (result == 0)) {
1254+
1255+ /* Write failed */
1256+
1257+ winbind_close_sock();
1258+ return -1;
1259+ }
1260+
1261+ nwritten += result;
1262+
1263+ } else {
1264+
1265+ /* Pipe has closed on remote end */
1266+
1267+ winbind_close_sock();
1268+ goto restart;
1269+ }
1270+ }
1271+
1272+ return nwritten;
1273+}
1274+
1275+/* Read data from winbindd socket */
1276+
1277+int winbind_read_sock(void *buffer, int count)
1278+{
1279+ int nread = 0;
1280+ int total_time = 0, selret;
1281+
1282+ if (winbindd_fd == -1) {
1283+ return -1;
1284+ }
1285+
1286+ /* Read data from socket */
1287+ while(nread < count) {
1288+ struct timeval tv;
1289+ fd_set r_fds;
1290+
1291+ /* Catch pipe close on other end by checking if a read()
1292+ call would not block by calling select(). */
1293+
1294+ FD_ZERO(&r_fds);
1295+ FD_SET(winbindd_fd, &r_fds);
1296+ ZERO_STRUCT(tv);
1297+ /* Wait for 5 seconds for a reply. May need to parameterise this... */
1298+ tv.tv_sec = 5;
1299+
1300+ if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
1301+ winbind_close_sock();
1302+ return -1; /* Select error */
1303+ }
1304+
1305+ if (selret == 0) {
1306+ /* Not ready for read yet... */
1307+ if (total_time >= 30) {
1308+ /* Timeout */
1309+ winbind_close_sock();
1310+ return -1;
1311+ }
1312+ total_time += 5;
1313+ continue;
1314+ }
1315+
1316+ if (FD_ISSET(winbindd_fd, &r_fds)) {
1317+
1318+ /* Do the Read */
1319+
1320+ int result = read(winbindd_fd, (char *)buffer + nread,
1321+ count - nread);
1322+
1323+ if ((result == -1) || (result == 0)) {
1324+
1325+ /* Read failed. I think the only useful thing we
1326+ can do here is just return -1 and fail since the
1327+ transaction has failed half way through. */
1328+
1329+ winbind_close_sock();
1330+ return -1;
1331+ }
1332+
1333+ nread += result;
1334+
1335+ }
1336+ }
1337+
1338+ return nread;
1339+}
1340+
1341+/* Read reply */
1342+
1343+int winbindd_read_reply(struct winbindd_response *response)
1344+{
1345+ int result1, result2 = 0;
1346+
1347+ if (!response) {
1348+ return -1;
1349+ }
1350+
1351+ /* Read fixed length response */
1352+
1353+ result1 = winbind_read_sock(response,
1354+ sizeof(struct winbindd_response));
1355+ if (result1 == -1) {
1356+ return -1;
1357+ }
1358+
1359+ /* We actually send the pointer value of the extra_data field from
1360+ the server. This has no meaning in the client's address space
1361+ so we clear it out. */
1362+
1363+ response->extra_data.data = NULL;
1364+
1365+ /* Read variable length response */
1366+
1367+ if (response->length > sizeof(struct winbindd_response)) {
1368+ int extra_data_len = response->length -
1369+ sizeof(struct winbindd_response);
1370+
1371+ /* Mallocate memory for extra data */
1372+
1373+ if (!(response->extra_data.data = malloc(extra_data_len))) {
1374+ return -1;
1375+ }
1376+
1377+ result2 = winbind_read_sock(response->extra_data.data,
1378+ extra_data_len);
1379+ if (result2 == -1) {
1380+ winbindd_free_response(response);
1381+ return -1;
1382+ }
1383+ }
1384+
1385+ /* Return total amount of data read */
1386+
1387+ return result1 + result2;
1388+}
1389+
1390+/*
1391+ * send simple types of requests
1392+ */
1393+
1394+NSS_STATUS winbindd_send_request(int req_type, int need_priv,
1395+ struct winbindd_request *request)
1396+{
1397+ struct winbindd_request lrequest;
1398+
1399+ /* Check for our tricky environment variable */
1400+
1401+ if (winbind_env_set()) {
1402+ return NSS_STATUS_NOTFOUND;
1403+ }
1404+
1405+ if (!request) {
1406+ ZERO_STRUCT(lrequest);
1407+ request = &lrequest;
1408+ }
1409+
1410+ /* Fill in request and send down pipe */
1411+
1412+ winbindd_init_request(request, req_type);
1413+
1414+ if (winbind_write_sock(request, sizeof(*request),
1415+ request->wb_flags & WBFLAG_RECURSE,
1416+ need_priv) == -1)
1417+ {
1418+ /* Set ENOENT for consistency. Required by some apps */
1419+ errno = ENOENT;
1420+
1421+ return NSS_STATUS_UNAVAIL;
1422+ }
1423+
1424+ if ((request->extra_len != 0) &&
1425+ (winbind_write_sock(request->extra_data.data,
1426+ request->extra_len,
1427+ request->wb_flags & WBFLAG_RECURSE,
1428+ need_priv) == -1))
1429+ {
1430+ /* Set ENOENT for consistency. Required by some apps */
1431+ errno = ENOENT;
1432+
1433+ return NSS_STATUS_UNAVAIL;
1434+ }
1435+
1436+ return NSS_STATUS_SUCCESS;
1437+}
1438+
1439+/*
1440+ * Get results from winbindd request
1441+ */
1442+
1443+NSS_STATUS winbindd_get_response(struct winbindd_response *response)
1444+{
1445+ struct winbindd_response lresponse;
1446+
1447+ if (!response) {
1448+ ZERO_STRUCT(lresponse);
1449+ response = &lresponse;
1450+ }
1451+
1452+ init_response(response);
1453+
1454+ /* Wait for reply */
1455+ if (winbindd_read_reply(response) == -1) {
1456+ /* Set ENOENT for consistency. Required by some apps */
1457+ errno = ENOENT;
1458+
1459+ return NSS_STATUS_UNAVAIL;
1460+ }
1461+
1462+ /* Throw away extra data if client didn't request it */
1463+ if (response == &lresponse) {
1464+ winbindd_free_response(response);
1465+ }
1466+
1467+ /* Copy reply data from socket */
1468+ if (response->result != WINBINDD_OK) {
1469+ return NSS_STATUS_NOTFOUND;
1470+ }
1471+
1472+ return NSS_STATUS_SUCCESS;
1473+}
1474+
1475+/* Handle simple types of requests */
1476+
1477+NSS_STATUS winbindd_request_response(int req_type,
1478+ struct winbindd_request *request,
1479+ struct winbindd_response *response)
1480+{
1481+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
1482+ int count = 0;
1483+
1484+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
1485+ status = winbindd_send_request(req_type, 0, request);
1486+ if (status != NSS_STATUS_SUCCESS)
1487+ return(status);
1488+ status = winbindd_get_response(response);
1489+ count += 1;
1490+ }
1491+
1492+ return status;
1493+}
1494+
1495+NSS_STATUS winbindd_priv_request_response(int req_type,
1496+ struct winbindd_request *request,
1497+ struct winbindd_response *response)
1498+{
1499+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
1500+ int count = 0;
1501+
1502+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
1503+ status = winbindd_send_request(req_type, 1, request);
1504+ if (status != NSS_STATUS_SUCCESS)
1505+ return(status);
1506+ status = winbindd_get_response(response);
1507+ count += 1;
1508+ }
1509+
1510+ return status;
1511+}
1512+
1513+/*************************************************************************
1514+ ************************************************************************/
1515+
1516+const char *nss_err_str(NSS_STATUS ret)
1517+{
1518+ switch (ret) {
1519+ case NSS_STATUS_TRYAGAIN:
1520+ return "NSS_STATUS_TRYAGAIN";
1521+ case NSS_STATUS_SUCCESS:
1522+ return "NSS_STATUS_SUCCESS";
1523+ case NSS_STATUS_NOTFOUND:
1524+ return "NSS_STATUS_NOTFOUND";
1525+ case NSS_STATUS_UNAVAIL:
1526+ return "NSS_STATUS_UNAVAIL";
1527+#ifdef NSS_STATUS_RETURN
1528+ case NSS_STATUS_RETURN:
1529+ return "NSS_STATUS_RETURN";
1530+#endif
1531+ default:
1532+ return "UNKNOWN RETURN CODE!!!!!!!";
1533+ }
1534+}
1535
1536=== added directory '.pc/security-CVE-2011-0719.patch/source3'
1537=== added directory '.pc/security-CVE-2011-0719.patch/source3/client'
1538=== added file '.pc/security-CVE-2011-0719.patch/source3/client/client.c'
1539--- .pc/security-CVE-2011-0719.patch/source3/client/client.c 1970-01-01 00:00:00 +0000
1540+++ .pc/security-CVE-2011-0719.patch/source3/client/client.c 2011-03-02 20:47:51 +0000
1541@@ -0,0 +1,5022 @@
1542+/*
1543+ Unix SMB/CIFS implementation.
1544+ SMB client
1545+ Copyright (C) Andrew Tridgell 1994-1998
1546+ Copyright (C) Simo Sorce 2001-2002
1547+ Copyright (C) Jelmer Vernooij 2003
1548+ Copyright (C) Gerald (Jerry) Carter 2004
1549+ Copyright (C) Jeremy Allison 1994-2007
1550+
1551+ This program is free software; you can redistribute it and/or modify
1552+ it under the terms of the GNU General Public License as published by
1553+ the Free Software Foundation; either version 3 of the License, or
1554+ (at your option) any later version.
1555+
1556+ This program is distributed in the hope that it will be useful,
1557+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1558+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1559+ GNU General Public License for more details.
1560+
1561+ You should have received a copy of the GNU General Public License
1562+ along with this program. If not, see <http://www.gnu.org/licenses/>.
1563+*/
1564+
1565+#include "includes.h"
1566+#include "client/client_proto.h"
1567+#include "include/rpc_client.h"
1568+#ifndef REGISTER
1569+#define REGISTER 0
1570+#endif
1571+
1572+extern int do_smb_browse(void); /* mDNS browsing */
1573+
1574+extern bool AllowDebugChange;
1575+extern bool override_logfile;
1576+extern char tar_type;
1577+
1578+static int port = 0;
1579+static char *service;
1580+static char *desthost;
1581+static char *calling_name;
1582+static bool grepable = false;
1583+static char *cmdstr = NULL;
1584+const char *cmd_ptr = NULL;
1585+
1586+static int io_bufsize = 524288;
1587+
1588+static int name_type = 0x20;
1589+static int max_protocol = PROTOCOL_NT1;
1590+
1591+static int process_tok(char *tok);
1592+static int cmd_help(void);
1593+
1594+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
1595+
1596+/* 30 second timeout on most commands */
1597+#define CLIENT_TIMEOUT (30*1000)
1598+#define SHORT_TIMEOUT (5*1000)
1599+
1600+/* value for unused fid field in trans2 secondary request */
1601+#define FID_UNUSED (0xFFFF)
1602+
1603+time_t newer_than = 0;
1604+static int archive_level = 0;
1605+
1606+static bool translation = false;
1607+static bool have_ip;
1608+
1609+/* clitar bits insert */
1610+extern int blocksize;
1611+extern bool tar_inc;
1612+extern bool tar_reset;
1613+/* clitar bits end */
1614+
1615+static bool prompt = true;
1616+
1617+static bool recurse = false;
1618+static bool showacls = false;
1619+bool lowercase = false;
1620+
1621+static struct sockaddr_storage dest_ss;
1622+static char dest_ss_str[INET6_ADDRSTRLEN];
1623+
1624+#define SEPARATORS " \t\n\r"
1625+
1626+static bool abort_mget = true;
1627+
1628+/* timing globals */
1629+uint64_t get_total_size = 0;
1630+unsigned int get_total_time_ms = 0;
1631+static uint64_t put_total_size = 0;
1632+static unsigned int put_total_time_ms = 0;
1633+
1634+/* totals globals */
1635+static double dir_total;
1636+
1637+/* encrypted state. */
1638+static bool smb_encrypt;
1639+
1640+/* root cli_state connection */
1641+
1642+struct cli_state *cli;
1643+
1644+static char CLI_DIRSEP_CHAR = '\\';
1645+static char CLI_DIRSEP_STR[] = { '\\', '\0' };
1646+
1647+/* Authentication for client connections. */
1648+struct user_auth_info *auth_info;
1649+
1650+/* Accessor functions for directory paths. */
1651+static char *fileselection;
1652+static const char *client_get_fileselection(void)
1653+{
1654+ if (fileselection) {
1655+ return fileselection;
1656+ }
1657+ return "";
1658+}
1659+
1660+static const char *client_set_fileselection(const char *new_fs)
1661+{
1662+ SAFE_FREE(fileselection);
1663+ if (new_fs) {
1664+ fileselection = SMB_STRDUP(new_fs);
1665+ }
1666+ return client_get_fileselection();
1667+}
1668+
1669+static char *cwd;
1670+static const char *client_get_cwd(void)
1671+{
1672+ if (cwd) {
1673+ return cwd;
1674+ }
1675+ return CLI_DIRSEP_STR;
1676+}
1677+
1678+static const char *client_set_cwd(const char *new_cwd)
1679+{
1680+ SAFE_FREE(cwd);
1681+ if (new_cwd) {
1682+ cwd = SMB_STRDUP(new_cwd);
1683+ }
1684+ return client_get_cwd();
1685+}
1686+
1687+static char *cur_dir;
1688+const char *client_get_cur_dir(void)
1689+{
1690+ if (cur_dir) {
1691+ return cur_dir;
1692+ }
1693+ return CLI_DIRSEP_STR;
1694+}
1695+
1696+const char *client_set_cur_dir(const char *newdir)
1697+{
1698+ SAFE_FREE(cur_dir);
1699+ if (newdir) {
1700+ cur_dir = SMB_STRDUP(newdir);
1701+ }
1702+ return client_get_cur_dir();
1703+}
1704+
1705+/****************************************************************************
1706+ Write to a local file with CR/LF->LF translation if appropriate. Return the
1707+ number taken from the buffer. This may not equal the number written.
1708+****************************************************************************/
1709+
1710+static int writefile(int f, char *b, int n)
1711+{
1712+ int i;
1713+
1714+ if (!translation) {
1715+ return write(f,b,n);
1716+ }
1717+
1718+ i = 0;
1719+ while (i < n) {
1720+ if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
1721+ b++;i++;
1722+ }
1723+ if (write(f, b, 1) != 1) {
1724+ break;
1725+ }
1726+ b++;
1727+ i++;
1728+ }
1729+
1730+ return(i);
1731+}
1732+
1733+/****************************************************************************
1734+ Read from a file with LF->CR/LF translation if appropriate. Return the
1735+ number read. read approx n bytes.
1736+****************************************************************************/
1737+
1738+static int readfile(uint8_t *b, int n, XFILE *f)
1739+{
1740+ int i;
1741+ int c;
1742+
1743+ if (!translation)
1744+ return x_fread(b,1,n,f);
1745+
1746+ i = 0;
1747+ while (i < (n - 1) && (i < BUFFER_SIZE)) {
1748+ if ((c = x_getc(f)) == EOF) {
1749+ break;
1750+ }
1751+
1752+ if (c == '\n') { /* change all LFs to CR/LF */
1753+ b[i++] = '\r';
1754+ }
1755+
1756+ b[i++] = c;
1757+ }
1758+
1759+ return(i);
1760+}
1761+
1762+struct push_state {
1763+ XFILE *f;
1764+ SMB_OFF_T nread;
1765+};
1766+
1767+static size_t push_source(uint8_t *buf, size_t n, void *priv)
1768+{
1769+ struct push_state *state = (struct push_state *)priv;
1770+ int result;
1771+
1772+ if (x_feof(state->f)) {
1773+ return 0;
1774+ }
1775+
1776+ result = readfile(buf, n, state->f);
1777+ state->nread += result;
1778+ return result;
1779+}
1780+
1781+/****************************************************************************
1782+ Send a message.
1783+****************************************************************************/
1784+
1785+static void send_message(const char *username)
1786+{
1787+ int total_len = 0;
1788+ int grp_id;
1789+
1790+ if (!cli_message_start(cli, desthost, username, &grp_id)) {
1791+ d_printf("message start: %s\n", cli_errstr(cli));
1792+ return;
1793+ }
1794+
1795+
1796+ d_printf("Connected. Type your message, ending it with a Control-D\n");
1797+
1798+ while (!feof(stdin) && total_len < 1600) {
1799+ int maxlen = MIN(1600 - total_len,127);
1800+ char msg[1024];
1801+ int l=0;
1802+ int c;
1803+
1804+ ZERO_ARRAY(msg);
1805+
1806+ for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
1807+ if (c == '\n')
1808+ msg[l++] = '\r';
1809+ msg[l] = c;
1810+ }
1811+
1812+ if ((total_len > 0) && (strlen(msg) == 0)) {
1813+ break;
1814+ }
1815+
1816+ if (!cli_message_text(cli, msg, l, grp_id)) {
1817+ d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
1818+ return;
1819+ }
1820+
1821+ total_len += l;
1822+ }
1823+
1824+ if (total_len >= 1600)
1825+ d_printf("the message was truncated to 1600 bytes\n");
1826+ else
1827+ d_printf("sent %d bytes\n",total_len);
1828+
1829+ if (!cli_message_end(cli, grp_id)) {
1830+ d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
1831+ return;
1832+ }
1833+}
1834+
1835+/****************************************************************************
1836+ Check the space on a device.
1837+****************************************************************************/
1838+
1839+static int do_dskattr(void)
1840+{
1841+ int total, bsize, avail;
1842+ struct cli_state *targetcli = NULL;
1843+ char *targetpath = NULL;
1844+ TALLOC_CTX *ctx = talloc_tos();
1845+
1846+ if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
1847+ d_printf("Error in dskattr: %s\n", cli_errstr(cli));
1848+ return 1;
1849+ }
1850+
1851+ if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
1852+ d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
1853+ return 1;
1854+ }
1855+
1856+ d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
1857+ total, bsize, avail);
1858+
1859+ return 0;
1860+}
1861+
1862+/****************************************************************************
1863+ Show cd/pwd.
1864+****************************************************************************/
1865+
1866+static int cmd_pwd(void)
1867+{
1868+ d_printf("Current directory is %s",service);
1869+ d_printf("%s\n",client_get_cur_dir());
1870+ return 0;
1871+}
1872+
1873+/****************************************************************************
1874+ Ensure name has correct directory separators.
1875+****************************************************************************/
1876+
1877+static void normalize_name(char *newdir)
1878+{
1879+ if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
1880+ string_replace(newdir,'/','\\');
1881+ }
1882+}
1883+
1884+/****************************************************************************
1885+ Change directory - inner section.
1886+****************************************************************************/
1887+
1888+static int do_cd(const char *new_dir)
1889+{
1890+ char *newdir = NULL;
1891+ char *saved_dir = NULL;
1892+ char *new_cd = NULL;
1893+ char *targetpath = NULL;
1894+ struct cli_state *targetcli = NULL;
1895+ SMB_STRUCT_STAT sbuf;
1896+ uint32 attributes;
1897+ int ret = 1;
1898+ TALLOC_CTX *ctx = talloc_stackframe();
1899+
1900+ newdir = talloc_strdup(ctx, new_dir);
1901+ if (!newdir) {
1902+ TALLOC_FREE(ctx);
1903+ return 1;
1904+ }
1905+
1906+ normalize_name(newdir);
1907+
1908+ /* Save the current directory in case the new directory is invalid */
1909+
1910+ saved_dir = talloc_strdup(ctx, client_get_cur_dir());
1911+ if (!saved_dir) {
1912+ TALLOC_FREE(ctx);
1913+ return 1;
1914+ }
1915+
1916+ if (*newdir == CLI_DIRSEP_CHAR) {
1917+ client_set_cur_dir(newdir);
1918+ new_cd = newdir;
1919+ } else {
1920+ new_cd = talloc_asprintf(ctx, "%s%s",
1921+ client_get_cur_dir(),
1922+ newdir);
1923+ if (!new_cd) {
1924+ goto out;
1925+ }
1926+ }
1927+
1928+ /* Ensure cur_dir ends in a DIRSEP */
1929+ if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
1930+ new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
1931+ if (!new_cd) {
1932+ goto out;
1933+ }
1934+ }
1935+ client_set_cur_dir(new_cd);
1936+
1937+ new_cd = clean_name(ctx, new_cd);
1938+ client_set_cur_dir(new_cd);
1939+
1940+ if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
1941+ d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
1942+ client_set_cur_dir(saved_dir);
1943+ goto out;
1944+ }
1945+
1946+ if (strequal(targetpath,CLI_DIRSEP_STR )) {
1947+ TALLOC_FREE(ctx);
1948+ return 0;
1949+ }
1950+
1951+ /* Use a trans2_qpathinfo to test directories for modern servers.
1952+ Except Win9x doesn't support the qpathinfo_basic() call..... */
1953+
1954+ if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
1955+ if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
1956+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
1957+ client_set_cur_dir(saved_dir);
1958+ goto out;
1959+ }
1960+
1961+ if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
1962+ d_printf("cd %s: not a directory\n", new_cd);
1963+ client_set_cur_dir(saved_dir);
1964+ goto out;
1965+ }
1966+ } else {
1967+ targetpath = talloc_asprintf(ctx,
1968+ "%s%s",
1969+ targetpath,
1970+ CLI_DIRSEP_STR );
1971+ if (!targetpath) {
1972+ client_set_cur_dir(saved_dir);
1973+ goto out;
1974+ }
1975+ targetpath = clean_name(ctx, targetpath);
1976+ if (!targetpath) {
1977+ client_set_cur_dir(saved_dir);
1978+ goto out;
1979+ }
1980+
1981+ if (!cli_chkpath(targetcli, targetpath)) {
1982+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
1983+ client_set_cur_dir(saved_dir);
1984+ goto out;
1985+ }
1986+ }
1987+
1988+ ret = 0;
1989+
1990+out:
1991+
1992+ TALLOC_FREE(ctx);
1993+ return ret;
1994+}
1995+
1996+/****************************************************************************
1997+ Change directory.
1998+****************************************************************************/
1999+
2000+static int cmd_cd(void)
2001+{
2002+ char *buf = NULL;
2003+ int rc = 0;
2004+
2005+ if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
2006+ rc = do_cd(buf);
2007+ } else {
2008+ d_printf("Current directory is %s\n",client_get_cur_dir());
2009+ }
2010+
2011+ return rc;
2012+}
2013+
2014+/****************************************************************************
2015+ Change directory.
2016+****************************************************************************/
2017+
2018+static int cmd_cd_oneup(void)
2019+{
2020+ return do_cd("..");
2021+}
2022+
2023+/*******************************************************************
2024+ Decide if a file should be operated on.
2025+********************************************************************/
2026+
2027+static bool do_this_one(file_info *finfo)
2028+{
2029+ if (!finfo->name) {
2030+ return false;
2031+ }
2032+
2033+ if (finfo->mode & aDIR) {
2034+ return true;
2035+ }
2036+
2037+ if (*client_get_fileselection() &&
2038+ !mask_match(finfo->name,client_get_fileselection(),false)) {
2039+ DEBUG(3,("mask_match %s failed\n", finfo->name));
2040+ return false;
2041+ }
2042+
2043+ if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
2044+ DEBUG(3,("newer_than %s failed\n", finfo->name));
2045+ return false;
2046+ }
2047+
2048+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
2049+ DEBUG(3,("archive %s failed\n", finfo->name));
2050+ return false;
2051+ }
2052+
2053+ return true;
2054+}
2055+
2056+/****************************************************************************
2057+ Display info about a file.
2058+****************************************************************************/
2059+
2060+static void display_finfo(file_info *finfo, const char *dir)
2061+{
2062+ time_t t;
2063+ TALLOC_CTX *ctx = talloc_tos();
2064+
2065+ if (!do_this_one(finfo)) {
2066+ return;
2067+ }
2068+
2069+ t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
2070+ if (!showacls) {
2071+ d_printf(" %-30s%7.7s %8.0f %s",
2072+ finfo->name,
2073+ attrib_string(finfo->mode),
2074+ (double)finfo->size,
2075+ time_to_asc(t));
2076+ dir_total += finfo->size;
2077+ } else {
2078+ char *afname = NULL;
2079+ int fnum;
2080+
2081+ /* skip if this is . or .. */
2082+ if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
2083+ return;
2084+ /* create absolute filename for cli_nt_create() FIXME */
2085+ afname = talloc_asprintf(ctx,
2086+ "%s%s%s",
2087+ dir,
2088+ CLI_DIRSEP_STR,
2089+ finfo->name);
2090+ if (!afname) {
2091+ return;
2092+ }
2093+ /* print file meta date header */
2094+ d_printf( "FILENAME:%s\n", finfo->name);
2095+ d_printf( "MODE:%s\n", attrib_string(finfo->mode));
2096+ d_printf( "SIZE:%.0f\n", (double)finfo->size);
2097+ d_printf( "MTIME:%s", time_to_asc(t));
2098+ fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
2099+ if (fnum == -1) {
2100+ DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
2101+ afname,
2102+ cli_errstr( finfo->cli)));
2103+ } else {
2104+ SEC_DESC *sd = NULL;
2105+ sd = cli_query_secdesc(finfo->cli, fnum, ctx);
2106+ if (!sd) {
2107+ DEBUG( 0, ("display_finfo() failed to "
2108+ "get security descriptor: %s",
2109+ cli_errstr( finfo->cli)));
2110+ } else {
2111+ display_sec_desc(sd);
2112+ }
2113+ TALLOC_FREE(sd);
2114+ }
2115+ TALLOC_FREE(afname);
2116+ }
2117+}
2118+
2119+/****************************************************************************
2120+ Accumulate size of a file.
2121+****************************************************************************/
2122+
2123+static void do_du(file_info *finfo, const char *dir)
2124+{
2125+ if (do_this_one(finfo)) {
2126+ dir_total += finfo->size;
2127+ }
2128+}
2129+
2130+static bool do_list_recurse;
2131+static bool do_list_dirs;
2132+static char *do_list_queue = 0;
2133+static long do_list_queue_size = 0;
2134+static long do_list_queue_start = 0;
2135+static long do_list_queue_end = 0;
2136+static void (*do_list_fn)(file_info *, const char *dir);
2137+
2138+/****************************************************************************
2139+ Functions for do_list_queue.
2140+****************************************************************************/
2141+
2142+/*
2143+ * The do_list_queue is a NUL-separated list of strings stored in a
2144+ * char*. Since this is a FIFO, we keep track of the beginning and
2145+ * ending locations of the data in the queue. When we overflow, we
2146+ * double the size of the char*. When the start of the data passes
2147+ * the midpoint, we move everything back. This is logically more
2148+ * complex than a linked list, but easier from a memory management
2149+ * angle. In any memory error condition, do_list_queue is reset.
2150+ * Functions check to ensure that do_list_queue is non-NULL before
2151+ * accessing it.
2152+ */
2153+
2154+static void reset_do_list_queue(void)
2155+{
2156+ SAFE_FREE(do_list_queue);
2157+ do_list_queue_size = 0;
2158+ do_list_queue_start = 0;
2159+ do_list_queue_end = 0;
2160+}
2161+
2162+static void init_do_list_queue(void)
2163+{
2164+ reset_do_list_queue();
2165+ do_list_queue_size = 1024;
2166+ do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
2167+ if (do_list_queue == 0) {
2168+ d_printf("malloc fail for size %d\n",
2169+ (int)do_list_queue_size);
2170+ reset_do_list_queue();
2171+ } else {
2172+ memset(do_list_queue, 0, do_list_queue_size);
2173+ }
2174+}
2175+
2176+static void adjust_do_list_queue(void)
2177+{
2178+ /*
2179+ * If the starting point of the queue is more than half way through,
2180+ * move everything toward the beginning.
2181+ */
2182+
2183+ if (do_list_queue == NULL) {
2184+ DEBUG(4,("do_list_queue is empty\n"));
2185+ do_list_queue_start = do_list_queue_end = 0;
2186+ return;
2187+ }
2188+
2189+ if (do_list_queue_start == do_list_queue_end) {
2190+ DEBUG(4,("do_list_queue is empty\n"));
2191+ do_list_queue_start = do_list_queue_end = 0;
2192+ *do_list_queue = '\0';
2193+ } else if (do_list_queue_start > (do_list_queue_size / 2)) {
2194+ DEBUG(4,("sliding do_list_queue backward\n"));
2195+ memmove(do_list_queue,
2196+ do_list_queue + do_list_queue_start,
2197+ do_list_queue_end - do_list_queue_start);
2198+ do_list_queue_end -= do_list_queue_start;
2199+ do_list_queue_start = 0;
2200+ }
2201+}
2202+
2203+static void add_to_do_list_queue(const char *entry)
2204+{
2205+ long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
2206+ while (new_end > do_list_queue_size) {
2207+ do_list_queue_size *= 2;
2208+ DEBUG(4,("enlarging do_list_queue to %d\n",
2209+ (int)do_list_queue_size));
2210+ do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
2211+ if (! do_list_queue) {
2212+ d_printf("failure enlarging do_list_queue to %d bytes\n",
2213+ (int)do_list_queue_size);
2214+ reset_do_list_queue();
2215+ } else {
2216+ memset(do_list_queue + do_list_queue_size / 2,
2217+ 0, do_list_queue_size / 2);
2218+ }
2219+ }
2220+ if (do_list_queue) {
2221+ safe_strcpy_base(do_list_queue + do_list_queue_end,
2222+ entry, do_list_queue, do_list_queue_size);
2223+ do_list_queue_end = new_end;
2224+ DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
2225+ entry, (int)do_list_queue_start, (int)do_list_queue_end));
2226+ }
2227+}
2228+
2229+static char *do_list_queue_head(void)
2230+{
2231+ return do_list_queue + do_list_queue_start;
2232+}
2233+
2234+static void remove_do_list_queue_head(void)
2235+{
2236+ if (do_list_queue_end > do_list_queue_start) {
2237+ do_list_queue_start += strlen(do_list_queue_head()) + 1;
2238+ adjust_do_list_queue();
2239+ DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
2240+ (int)do_list_queue_start, (int)do_list_queue_end));
2241+ }
2242+}
2243+
2244+static int do_list_queue_empty(void)
2245+{
2246+ return (! (do_list_queue && *do_list_queue));
2247+}
2248+
2249+/****************************************************************************
2250+ A helper for do_list.
2251+****************************************************************************/
2252+
2253+static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
2254+{
2255+ TALLOC_CTX *ctx = talloc_tos();
2256+ char *dir = NULL;
2257+ char *dir_end = NULL;
2258+
2259+ /* Work out the directory. */
2260+ dir = talloc_strdup(ctx, mask);
2261+ if (!dir) {
2262+ return;
2263+ }
2264+ if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
2265+ *dir_end = '\0';
2266+ }
2267+
2268+ if (f->mode & aDIR) {
2269+ if (do_list_dirs && do_this_one(f)) {
2270+ do_list_fn(f, dir);
2271+ }
2272+ if (do_list_recurse &&
2273+ f->name &&
2274+ !strequal(f->name,".") &&
2275+ !strequal(f->name,"..")) {
2276+ char *mask2 = NULL;
2277+ char *p = NULL;
2278+
2279+ if (!f->name[0]) {
2280+ d_printf("Empty dir name returned. Possible server misconfiguration.\n");
2281+ TALLOC_FREE(dir);
2282+ return;
2283+ }
2284+
2285+ mask2 = talloc_asprintf(ctx,
2286+ "%s%s",
2287+ mntpoint,
2288+ mask);
2289+ if (!mask2) {
2290+ TALLOC_FREE(dir);
2291+ return;
2292+ }
2293+ p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
2294+ if (p) {
2295+ p[1] = 0;
2296+ } else {
2297+ mask2[0] = '\0';
2298+ }
2299+ mask2 = talloc_asprintf_append(mask2,
2300+ "%s%s*",
2301+ f->name,
2302+ CLI_DIRSEP_STR);
2303+ if (!mask2) {
2304+ TALLOC_FREE(dir);
2305+ return;
2306+ }
2307+ add_to_do_list_queue(mask2);
2308+ TALLOC_FREE(mask2);
2309+ }
2310+ TALLOC_FREE(dir);
2311+ return;
2312+ }
2313+
2314+ if (do_this_one(f)) {
2315+ do_list_fn(f,dir);
2316+ }
2317+ TALLOC_FREE(dir);
2318+}
2319+
2320+/****************************************************************************
2321+ A wrapper around cli_list that adds recursion.
2322+****************************************************************************/
2323+
2324+void do_list(const char *mask,
2325+ uint16 attribute,
2326+ void (*fn)(file_info *, const char *dir),
2327+ bool rec,
2328+ bool dirs)
2329+{
2330+ static int in_do_list = 0;
2331+ TALLOC_CTX *ctx = talloc_tos();
2332+ struct cli_state *targetcli = NULL;
2333+ char *targetpath = NULL;
2334+
2335+ if (in_do_list && rec) {
2336+ fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
2337+ exit(1);
2338+ }
2339+
2340+ in_do_list = 1;
2341+
2342+ do_list_recurse = rec;
2343+ do_list_dirs = dirs;
2344+ do_list_fn = fn;
2345+
2346+ if (rec) {
2347+ init_do_list_queue();
2348+ add_to_do_list_queue(mask);
2349+
2350+ while (!do_list_queue_empty()) {
2351+ /*
2352+ * Need to copy head so that it doesn't become
2353+ * invalid inside the call to cli_list. This
2354+ * would happen if the list were expanded
2355+ * during the call.
2356+ * Fix from E. Jay Berkenbilt (ejb@ql.org)
2357+ */
2358+ char *head = talloc_strdup(ctx, do_list_queue_head());
2359+
2360+ if (!head) {
2361+ return;
2362+ }
2363+
2364+ /* check for dfs */
2365+
2366+ if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
2367+ d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
2368+ remove_do_list_queue_head();
2369+ continue;
2370+ }
2371+
2372+ cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
2373+ remove_do_list_queue_head();
2374+ if ((! do_list_queue_empty()) && (fn == display_finfo)) {
2375+ char *next_file = do_list_queue_head();
2376+ char *save_ch = 0;
2377+ if ((strlen(next_file) >= 2) &&
2378+ (next_file[strlen(next_file) - 1] == '*') &&
2379+ (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
2380+ save_ch = next_file +
2381+ strlen(next_file) - 2;
2382+ *save_ch = '\0';
2383+ if (showacls) {
2384+ /* cwd is only used if showacls is on */
2385+ client_set_cwd(next_file);
2386+ }
2387+ }
2388+ if (!showacls) /* don't disturbe the showacls output */
2389+ d_printf("\n%s\n",next_file);
2390+ if (save_ch) {
2391+ *save_ch = CLI_DIRSEP_CHAR;
2392+ }
2393+ }
2394+ TALLOC_FREE(head);
2395+ TALLOC_FREE(targetpath);
2396+ }
2397+ } else {
2398+ /* check for dfs */
2399+ if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
2400+ if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
2401+ d_printf("%s listing %s\n",
2402+ cli_errstr(targetcli), targetpath);
2403+ }
2404+ TALLOC_FREE(targetpath);
2405+ } else {
2406+ d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
2407+ }
2408+ }
2409+
2410+ in_do_list = 0;
2411+ reset_do_list_queue();
2412+}
2413+
2414+/****************************************************************************
2415+ Get a directory listing.
2416+****************************************************************************/
2417+
2418+static int cmd_dir(void)
2419+{
2420+ TALLOC_CTX *ctx = talloc_tos();
2421+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
2422+ char *mask = NULL;
2423+ char *buf = NULL;
2424+ int rc = 1;
2425+
2426+ dir_total = 0;
2427+ mask = talloc_strdup(ctx, client_get_cur_dir());
2428+ if (!mask) {
2429+ return 1;
2430+ }
2431+
2432+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2433+ normalize_name(buf);
2434+ if (*buf == CLI_DIRSEP_CHAR) {
2435+ mask = talloc_strdup(ctx, buf);
2436+ } else {
2437+ mask = talloc_asprintf_append(mask, "%s", buf);
2438+ }
2439+ } else {
2440+ mask = talloc_asprintf_append(mask, "*");
2441+ }
2442+ if (!mask) {
2443+ return 1;
2444+ }
2445+
2446+ if (showacls) {
2447+ /* cwd is only used if showacls is on */
2448+ client_set_cwd(client_get_cur_dir());
2449+ }
2450+
2451+ do_list(mask, attribute, display_finfo, recurse, true);
2452+
2453+ rc = do_dskattr();
2454+
2455+ DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
2456+
2457+ return rc;
2458+}
2459+
2460+/****************************************************************************
2461+ Get a directory listing.
2462+****************************************************************************/
2463+
2464+static int cmd_du(void)
2465+{
2466+ TALLOC_CTX *ctx = talloc_tos();
2467+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
2468+ char *mask = NULL;
2469+ char *buf = NULL;
2470+ int rc = 1;
2471+
2472+ dir_total = 0;
2473+ mask = talloc_strdup(ctx, client_get_cur_dir());
2474+ if (!mask) {
2475+ return 1;
2476+ }
2477+ if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
2478+ mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
2479+ if (!mask) {
2480+ return 1;
2481+ }
2482+ }
2483+
2484+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2485+ normalize_name(buf);
2486+ if (*buf == CLI_DIRSEP_CHAR) {
2487+ mask = talloc_strdup(ctx, buf);
2488+ } else {
2489+ mask = talloc_asprintf_append(mask, "%s", buf);
2490+ }
2491+ } else {
2492+ mask = talloc_strdup(ctx, "*");
2493+ }
2494+
2495+ do_list(mask, attribute, do_du, recurse, true);
2496+
2497+ rc = do_dskattr();
2498+
2499+ d_printf("Total number of bytes: %.0f\n", dir_total);
2500+
2501+ return rc;
2502+}
2503+
2504+static int cmd_echo(void)
2505+{
2506+ TALLOC_CTX *ctx = talloc_tos();
2507+ char *num;
2508+ char *data;
2509+ NTSTATUS status;
2510+
2511+ if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
2512+ || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
2513+ d_printf("echo <num> <data>\n");
2514+ return 1;
2515+ }
2516+
2517+ status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
2518+
2519+ if (!NT_STATUS_IS_OK(status)) {
2520+ d_printf("echo failed: %s\n", nt_errstr(status));
2521+ return 1;
2522+ }
2523+
2524+ return 0;
2525+}
2526+
2527+/****************************************************************************
2528+ Get a file from rname to lname
2529+****************************************************************************/
2530+
2531+static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
2532+{
2533+ int *pfd = (int *)priv;
2534+ if (writefile(*pfd, buf, n) == -1) {
2535+ return map_nt_error_from_unix(errno);
2536+ }
2537+ return NT_STATUS_OK;
2538+}
2539+
2540+static int do_get(const char *rname, const char *lname_in, bool reget)
2541+{
2542+ TALLOC_CTX *ctx = talloc_tos();
2543+ int handle = 0, fnum;
2544+ bool newhandle = false;
2545+ struct timeval tp_start;
2546+ uint16 attr;
2547+ SMB_OFF_T size;
2548+ off_t start = 0;
2549+ SMB_OFF_T nread = 0;
2550+ int rc = 0;
2551+ struct cli_state *targetcli = NULL;
2552+ char *targetname = NULL;
2553+ char *lname = NULL;
2554+ NTSTATUS status;
2555+
2556+ lname = talloc_strdup(ctx, lname_in);
2557+ if (!lname) {
2558+ return 1;
2559+ }
2560+
2561+ if (lowercase) {
2562+ strlower_m(lname);
2563+ }
2564+
2565+ if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
2566+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
2567+ return 1;
2568+ }
2569+
2570+ GetTimeOfDay(&tp_start);
2571+
2572+ fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
2573+
2574+ if (fnum == -1) {
2575+ d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
2576+ return 1;
2577+ }
2578+
2579+ if(!strcmp(lname,"-")) {
2580+ handle = fileno(stdout);
2581+ } else {
2582+ if (reget) {
2583+ handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
2584+ if (handle >= 0) {
2585+ start = sys_lseek(handle, 0, SEEK_END);
2586+ if (start == -1) {
2587+ d_printf("Error seeking local file\n");
2588+ return 1;
2589+ }
2590+ }
2591+ } else {
2592+ handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
2593+ }
2594+ newhandle = true;
2595+ }
2596+ if (handle < 0) {
2597+ d_printf("Error opening local file %s\n",lname);
2598+ return 1;
2599+ }
2600+
2601+
2602+ if (!cli_qfileinfo(targetcli, fnum,
2603+ &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
2604+ !cli_getattrE(targetcli, fnum,
2605+ &attr, &size, NULL, NULL, NULL)) {
2606+ d_printf("getattrib: %s\n",cli_errstr(targetcli));
2607+ return 1;
2608+ }
2609+
2610+ DEBUG(1,("getting file %s of size %.0f as %s ",
2611+ rname, (double)size, lname));
2612+
2613+ status = cli_pull(targetcli, fnum, start, size, io_bufsize,
2614+ writefile_sink, (void *)&handle, &nread);
2615+ if (!NT_STATUS_IS_OK(status)) {
2616+ d_fprintf(stderr, "parallel_read returned %s\n",
2617+ nt_errstr(status));
2618+ cli_close(targetcli, fnum);
2619+ return 1;
2620+ }
2621+
2622+ if (!cli_close(targetcli, fnum)) {
2623+ d_printf("Error %s closing remote file\n",cli_errstr(cli));
2624+ rc = 1;
2625+ }
2626+
2627+ if (newhandle) {
2628+ close(handle);
2629+ }
2630+
2631+ if (archive_level >= 2 && (attr & aARCH)) {
2632+ cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
2633+ }
2634+
2635+ {
2636+ struct timeval tp_end;
2637+ int this_time;
2638+
2639+ GetTimeOfDay(&tp_end);
2640+ this_time =
2641+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
2642+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
2643+ get_total_time_ms += this_time;
2644+ get_total_size += nread;
2645+
2646+ DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
2647+ nread / (1.024*this_time + 1.0e-4),
2648+ get_total_size / (1.024*get_total_time_ms)));
2649+ }
2650+
2651+ TALLOC_FREE(targetname);
2652+ return rc;
2653+}
2654+
2655+/****************************************************************************
2656+ Get a file.
2657+****************************************************************************/
2658+
2659+static int cmd_get(void)
2660+{
2661+ TALLOC_CTX *ctx = talloc_tos();
2662+ char *lname = NULL;
2663+ char *rname = NULL;
2664+ char *fname = NULL;
2665+
2666+ rname = talloc_strdup(ctx, client_get_cur_dir());
2667+ if (!rname) {
2668+ return 1;
2669+ }
2670+
2671+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
2672+ d_printf("get <filename> [localname]\n");
2673+ return 1;
2674+ }
2675+ rname = talloc_asprintf_append(rname, "%s", fname);
2676+ if (!rname) {
2677+ return 1;
2678+ }
2679+ rname = clean_name(ctx, rname);
2680+ if (!rname) {
2681+ return 1;
2682+ }
2683+
2684+ next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
2685+ if (!lname) {
2686+ lname = fname;
2687+ }
2688+
2689+ return do_get(rname, lname, false);
2690+}
2691+
2692+/****************************************************************************
2693+ Do an mget operation on one file.
2694+****************************************************************************/
2695+
2696+static void do_mget(file_info *finfo, const char *dir)
2697+{
2698+ TALLOC_CTX *ctx = talloc_tos();
2699+ char *rname = NULL;
2700+ char *quest = NULL;
2701+ char *saved_curdir = NULL;
2702+ char *mget_mask = NULL;
2703+ char *new_cd = NULL;
2704+
2705+ if (!finfo->name) {
2706+ return;
2707+ }
2708+
2709+ if (strequal(finfo->name,".") || strequal(finfo->name,".."))
2710+ return;
2711+
2712+ if (abort_mget) {
2713+ d_printf("mget aborted\n");
2714+ return;
2715+ }
2716+
2717+ if (finfo->mode & aDIR) {
2718+ if (asprintf(&quest,
2719+ "Get directory %s? ",finfo->name) < 0) {
2720+ return;
2721+ }
2722+ } else {
2723+ if (asprintf(&quest,
2724+ "Get file %s? ",finfo->name) < 0) {
2725+ return;
2726+ }
2727+ }
2728+
2729+ if (prompt && !yesno(quest)) {
2730+ SAFE_FREE(quest);
2731+ return;
2732+ }
2733+ SAFE_FREE(quest);
2734+
2735+ if (!(finfo->mode & aDIR)) {
2736+ rname = talloc_asprintf(ctx,
2737+ "%s%s",
2738+ client_get_cur_dir(),
2739+ finfo->name);
2740+ if (!rname) {
2741+ return;
2742+ }
2743+ do_get(rname, finfo->name, false);
2744+ TALLOC_FREE(rname);
2745+ return;
2746+ }
2747+
2748+ /* handle directories */
2749+ saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
2750+ if (!saved_curdir) {
2751+ return;
2752+ }
2753+
2754+ new_cd = talloc_asprintf(ctx,
2755+ "%s%s%s",
2756+ client_get_cur_dir(),
2757+ finfo->name,
2758+ CLI_DIRSEP_STR);
2759+ if (!new_cd) {
2760+ return;
2761+ }
2762+ client_set_cur_dir(new_cd);
2763+
2764+ string_replace(finfo->name,'\\','/');
2765+ if (lowercase) {
2766+ strlower_m(finfo->name);
2767+ }
2768+
2769+ if (!directory_exist(finfo->name) &&
2770+ mkdir(finfo->name,0777) != 0) {
2771+ d_printf("failed to create directory %s\n",finfo->name);
2772+ client_set_cur_dir(saved_curdir);
2773+ return;
2774+ }
2775+
2776+ if (chdir(finfo->name) != 0) {
2777+ d_printf("failed to chdir to directory %s\n",finfo->name);
2778+ client_set_cur_dir(saved_curdir);
2779+ return;
2780+ }
2781+
2782+ mget_mask = talloc_asprintf(ctx,
2783+ "%s*",
2784+ client_get_cur_dir());
2785+
2786+ if (!mget_mask) {
2787+ return;
2788+ }
2789+
2790+ do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
2791+ if (chdir("..") == -1) {
2792+ d_printf("do_mget: failed to chdir to .. (error %s)\n",
2793+ strerror(errno) );
2794+ }
2795+ client_set_cur_dir(saved_curdir);
2796+ TALLOC_FREE(mget_mask);
2797+ TALLOC_FREE(saved_curdir);
2798+ TALLOC_FREE(new_cd);
2799+}
2800+
2801+/****************************************************************************
2802+ View the file using the pager.
2803+****************************************************************************/
2804+
2805+static int cmd_more(void)
2806+{
2807+ TALLOC_CTX *ctx = talloc_tos();
2808+ char *rname = NULL;
2809+ char *fname = NULL;
2810+ char *lname = NULL;
2811+ char *pager_cmd = NULL;
2812+ const char *pager;
2813+ int fd;
2814+ int rc = 0;
2815+
2816+ rname = talloc_strdup(ctx, client_get_cur_dir());
2817+ if (!rname) {
2818+ return 1;
2819+ }
2820+
2821+ lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
2822+ if (!lname) {
2823+ return 1;
2824+ }
2825+ fd = smb_mkstemp(lname);
2826+ if (fd == -1) {
2827+ d_printf("failed to create temporary file for more\n");
2828+ return 1;
2829+ }
2830+ close(fd);
2831+
2832+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
2833+ d_printf("more <filename>\n");
2834+ unlink(lname);
2835+ return 1;
2836+ }
2837+ rname = talloc_asprintf_append(rname, "%s", fname);
2838+ if (!rname) {
2839+ return 1;
2840+ }
2841+ rname = clean_name(ctx,rname);
2842+ if (!rname) {
2843+ return 1;
2844+ }
2845+
2846+ rc = do_get(rname, lname, false);
2847+
2848+ pager=getenv("PAGER");
2849+
2850+ pager_cmd = talloc_asprintf(ctx,
2851+ "%s %s",
2852+ (pager? pager:PAGER),
2853+ lname);
2854+ if (!pager_cmd) {
2855+ return 1;
2856+ }
2857+ if (system(pager_cmd) == -1) {
2858+ d_printf("system command '%s' returned -1\n",
2859+ pager_cmd);
2860+ }
2861+ unlink(lname);
2862+
2863+ return rc;
2864+}
2865+
2866+/****************************************************************************
2867+ Do a mget command.
2868+****************************************************************************/
2869+
2870+static int cmd_mget(void)
2871+{
2872+ TALLOC_CTX *ctx = talloc_tos();
2873+ uint16 attribute = aSYSTEM | aHIDDEN;
2874+ char *mget_mask = NULL;
2875+ char *buf = NULL;
2876+
2877+ if (recurse) {
2878+ attribute |= aDIR;
2879+ }
2880+
2881+ abort_mget = false;
2882+
2883+ while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2884+ mget_mask = talloc_strdup(ctx, client_get_cur_dir());
2885+ if (!mget_mask) {
2886+ return 1;
2887+ }
2888+ if (*buf == CLI_DIRSEP_CHAR) {
2889+ mget_mask = talloc_strdup(ctx, buf);
2890+ } else {
2891+ mget_mask = talloc_asprintf_append(mget_mask,
2892+ "%s", buf);
2893+ }
2894+ if (!mget_mask) {
2895+ return 1;
2896+ }
2897+ do_list(mget_mask, attribute, do_mget, false, true);
2898+ }
2899+
2900+ if (mget_mask == NULL) {
2901+ d_printf("nothing to mget\n");
2902+ return 0;
2903+ }
2904+
2905+ if (!*mget_mask) {
2906+ mget_mask = talloc_asprintf(ctx,
2907+ "%s*",
2908+ client_get_cur_dir());
2909+ if (!mget_mask) {
2910+ return 1;
2911+ }
2912+ do_list(mget_mask, attribute, do_mget, false, true);
2913+ }
2914+
2915+ return 0;
2916+}
2917+
2918+/****************************************************************************
2919+ Make a directory of name "name".
2920+****************************************************************************/
2921+
2922+static bool do_mkdir(const char *name)
2923+{
2924+ TALLOC_CTX *ctx = talloc_tos();
2925+ struct cli_state *targetcli;
2926+ char *targetname = NULL;
2927+
2928+ if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
2929+ d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
2930+ return false;
2931+ }
2932+
2933+ if (!cli_mkdir(targetcli, targetname)) {
2934+ d_printf("%s making remote directory %s\n",
2935+ cli_errstr(targetcli),name);
2936+ return false;
2937+ }
2938+
2939+ return true;
2940+}
2941+
2942+/****************************************************************************
2943+ Show 8.3 name of a file.
2944+****************************************************************************/
2945+
2946+static bool do_altname(const char *name)
2947+{
2948+ fstring altname;
2949+
2950+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
2951+ d_printf("%s getting alt name for %s\n",
2952+ cli_errstr(cli),name);
2953+ return false;
2954+ }
2955+ d_printf("%s\n", altname);
2956+
2957+ return true;
2958+}
2959+
2960+/****************************************************************************
2961+ Exit client.
2962+****************************************************************************/
2963+
2964+static int cmd_quit(void)
2965+{
2966+ cli_shutdown(cli);
2967+ exit(0);
2968+ /* NOTREACHED */
2969+ return 0;
2970+}
2971+
2972+/****************************************************************************
2973+ Make a directory.
2974+****************************************************************************/
2975+
2976+static int cmd_mkdir(void)
2977+{
2978+ TALLOC_CTX *ctx = talloc_tos();
2979+ char *mask = NULL;
2980+ char *buf = NULL;
2981+
2982+ mask = talloc_strdup(ctx, client_get_cur_dir());
2983+ if (!mask) {
2984+ return 1;
2985+ }
2986+
2987+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2988+ if (!recurse) {
2989+ d_printf("mkdir <dirname>\n");
2990+ }
2991+ return 1;
2992+ }
2993+ mask = talloc_asprintf_append(mask, "%s", buf);
2994+ if (!mask) {
2995+ return 1;
2996+ }
2997+
2998+ if (recurse) {
2999+ char *ddir = NULL;
3000+ char *ddir2 = NULL;
3001+ struct cli_state *targetcli;
3002+ char *targetname = NULL;
3003+ char *p = NULL;
3004+ char *saveptr;
3005+
3006+ ddir2 = talloc_strdup(ctx, "");
3007+ if (!ddir2) {
3008+ return 1;
3009+ }
3010+
3011+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3012+ return 1;
3013+ }
3014+
3015+ ddir = talloc_strdup(ctx, targetname);
3016+ if (!ddir) {
3017+ return 1;
3018+ }
3019+ trim_char(ddir,'.','\0');
3020+ p = strtok_r(ddir, "/\\", &saveptr);
3021+ while (p) {
3022+ ddir2 = talloc_asprintf_append(ddir2, "%s", p);
3023+ if (!ddir2) {
3024+ return 1;
3025+ }
3026+ if (!cli_chkpath(targetcli, ddir2)) {
3027+ do_mkdir(ddir2);
3028+ }
3029+ ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
3030+ if (!ddir2) {
3031+ return 1;
3032+ }
3033+ p = strtok_r(NULL, "/\\", &saveptr);
3034+ }
3035+ } else {
3036+ do_mkdir(mask);
3037+ }
3038+
3039+ return 0;
3040+}
3041+
3042+/****************************************************************************
3043+ Show alt name.
3044+****************************************************************************/
3045+
3046+static int cmd_altname(void)
3047+{
3048+ TALLOC_CTX *ctx = talloc_tos();
3049+ char *name;
3050+ char *buf;
3051+
3052+ name = talloc_strdup(ctx, client_get_cur_dir());
3053+ if (!name) {
3054+ return 1;
3055+ }
3056+
3057+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3058+ d_printf("altname <file>\n");
3059+ return 1;
3060+ }
3061+ name = talloc_asprintf_append(name, "%s", buf);
3062+ if (!name) {
3063+ return 1;
3064+ }
3065+ do_altname(name);
3066+ return 0;
3067+}
3068+
3069+/****************************************************************************
3070+ Show all info we can get
3071+****************************************************************************/
3072+
3073+static int do_allinfo(const char *name)
3074+{
3075+ fstring altname;
3076+ struct timespec b_time, a_time, m_time, c_time;
3077+ SMB_OFF_T size;
3078+ uint16_t mode;
3079+ SMB_INO_T ino;
3080+ NTTIME tmp;
3081+ unsigned int num_streams;
3082+ struct stream_struct *streams;
3083+ unsigned int i;
3084+
3085+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
3086+ d_printf("%s getting alt name for %s\n",
3087+ cli_errstr(cli),name);
3088+ return false;
3089+ }
3090+ d_printf("altname: %s\n", altname);
3091+
3092+ if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
3093+ &size, &mode, &ino)) {
3094+ d_printf("%s getting pathinfo for %s\n",
3095+ cli_errstr(cli),name);
3096+ return false;
3097+ }
3098+
3099+ unix_timespec_to_nt_time(&tmp, b_time);
3100+ d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
3101+
3102+ unix_timespec_to_nt_time(&tmp, a_time);
3103+ d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
3104+
3105+ unix_timespec_to_nt_time(&tmp, m_time);
3106+ d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
3107+
3108+ unix_timespec_to_nt_time(&tmp, c_time);
3109+ d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
3110+
3111+ if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
3112+ &streams)) {
3113+ d_printf("%s getting streams for %s\n",
3114+ cli_errstr(cli),name);
3115+ return false;
3116+ }
3117+
3118+ for (i=0; i<num_streams; i++) {
3119+ d_printf("stream: [%s], %lld bytes\n", streams[i].name,
3120+ (unsigned long long)streams[i].size);
3121+ }
3122+
3123+ return 0;
3124+}
3125+
3126+/****************************************************************************
3127+ Show all info we can get
3128+****************************************************************************/
3129+
3130+static int cmd_allinfo(void)
3131+{
3132+ TALLOC_CTX *ctx = talloc_tos();
3133+ char *name;
3134+ char *buf;
3135+
3136+ name = talloc_strdup(ctx, client_get_cur_dir());
3137+ if (!name) {
3138+ return 1;
3139+ }
3140+
3141+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3142+ d_printf("allinfo <file>\n");
3143+ return 1;
3144+ }
3145+ name = talloc_asprintf_append(name, "%s", buf);
3146+ if (!name) {
3147+ return 1;
3148+ }
3149+
3150+ do_allinfo(name);
3151+
3152+ return 0;
3153+}
3154+
3155+/****************************************************************************
3156+ Put a single file.
3157+****************************************************************************/
3158+
3159+static int do_put(const char *rname, const char *lname, bool reput)
3160+{
3161+ TALLOC_CTX *ctx = talloc_tos();
3162+ int fnum;
3163+ XFILE *f;
3164+ SMB_OFF_T start = 0;
3165+ int rc = 0;
3166+ struct timeval tp_start;
3167+ struct cli_state *targetcli;
3168+ char *targetname = NULL;
3169+ struct push_state state;
3170+ NTSTATUS status;
3171+
3172+ if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
3173+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
3174+ return 1;
3175+ }
3176+
3177+ GetTimeOfDay(&tp_start);
3178+
3179+ if (reput) {
3180+ fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
3181+ if (fnum >= 0) {
3182+ if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
3183+ !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
3184+ d_printf("getattrib: %s\n",cli_errstr(cli));
3185+ return 1;
3186+ }
3187+ }
3188+ } else {
3189+ fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
3190+ }
3191+
3192+ if (fnum == -1) {
3193+ d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
3194+ return 1;
3195+ }
3196+
3197+ /* allow files to be piped into smbclient
3198+ jdblair 24.jun.98
3199+
3200+ Note that in this case this function will exit(0) rather
3201+ than returning. */
3202+ if (!strcmp(lname, "-")) {
3203+ f = x_stdin;
3204+ /* size of file is not known */
3205+ } else {
3206+ f = x_fopen(lname,O_RDONLY, 0);
3207+ if (f && reput) {
3208+ if (x_tseek(f, start, SEEK_SET) == -1) {
3209+ d_printf("Error seeking local file\n");
3210+ return 1;
3211+ }
3212+ }
3213+ }
3214+
3215+ if (!f) {
3216+ d_printf("Error opening local file %s\n",lname);
3217+ return 1;
3218+ }
3219+
3220+ DEBUG(1,("putting file %s as %s ",lname,
3221+ rname));
3222+
3223+ x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
3224+
3225+ state.f = f;
3226+ state.nread = 0;
3227+
3228+ status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
3229+ &state);
3230+ if (!NT_STATUS_IS_OK(status)) {
3231+ d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
3232+ }
3233+
3234+ if (!cli_close(targetcli, fnum)) {
3235+ d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
3236+ x_fclose(f);
3237+ return 1;
3238+ }
3239+
3240+ if (f != x_stdin) {
3241+ x_fclose(f);
3242+ }
3243+
3244+ {
3245+ struct timeval tp_end;
3246+ int this_time;
3247+
3248+ GetTimeOfDay(&tp_end);
3249+ this_time =
3250+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
3251+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
3252+ put_total_time_ms += this_time;
3253+ put_total_size += state.nread;
3254+
3255+ DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
3256+ state.nread / (1.024*this_time + 1.0e-4),
3257+ put_total_size / (1.024*put_total_time_ms)));
3258+ }
3259+
3260+ if (f == x_stdin) {
3261+ cli_shutdown(cli);
3262+ exit(0);
3263+ }
3264+
3265+ return rc;
3266+}
3267+
3268+/****************************************************************************
3269+ Put a file.
3270+****************************************************************************/
3271+
3272+static int cmd_put(void)
3273+{
3274+ TALLOC_CTX *ctx = talloc_tos();
3275+ char *lname;
3276+ char *rname;
3277+ char *buf;
3278+
3279+ rname = talloc_strdup(ctx, client_get_cur_dir());
3280+ if (!rname) {
3281+ return 1;
3282+ }
3283+
3284+ if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
3285+ d_printf("put <filename>\n");
3286+ return 1;
3287+ }
3288+
3289+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3290+ rname = talloc_asprintf_append(rname, "%s", buf);
3291+ } else {
3292+ rname = talloc_asprintf_append(rname, "%s", lname);
3293+ }
3294+ if (!rname) {
3295+ return 1;
3296+ }
3297+
3298+ rname = clean_name(ctx, rname);
3299+ if (!rname) {
3300+ return 1;
3301+ }
3302+
3303+ {
3304+ SMB_STRUCT_STAT st;
3305+ /* allow '-' to represent stdin
3306+ jdblair, 24.jun.98 */
3307+ if (!file_exist_stat(lname,&st) &&
3308+ (strcmp(lname,"-"))) {
3309+ d_printf("%s does not exist\n",lname);
3310+ return 1;
3311+ }
3312+ }
3313+
3314+ return do_put(rname, lname, false);
3315+}
3316+
3317+/*************************************
3318+ File list structure.
3319+*************************************/
3320+
3321+static struct file_list {
3322+ struct file_list *prev, *next;
3323+ char *file_path;
3324+ bool isdir;
3325+} *file_list;
3326+
3327+/****************************************************************************
3328+ Free a file_list structure.
3329+****************************************************************************/
3330+
3331+static void free_file_list (struct file_list *l_head)
3332+{
3333+ struct file_list *list, *next;
3334+
3335+ for (list = l_head; list; list = next) {
3336+ next = list->next;
3337+ DLIST_REMOVE(l_head, list);
3338+ SAFE_FREE(list->file_path);
3339+ SAFE_FREE(list);
3340+ }
3341+}
3342+
3343+/****************************************************************************
3344+ Seek in a directory/file list until you get something that doesn't start with
3345+ the specified name.
3346+****************************************************************************/
3347+
3348+static bool seek_list(struct file_list *list, char *name)
3349+{
3350+ while (list) {
3351+ trim_string(list->file_path,"./","\n");
3352+ if (strncmp(list->file_path, name, strlen(name)) != 0) {
3353+ return true;
3354+ }
3355+ list = list->next;
3356+ }
3357+
3358+ return false;
3359+}
3360+
3361+/****************************************************************************
3362+ Set the file selection mask.
3363+****************************************************************************/
3364+
3365+static int cmd_select(void)
3366+{
3367+ TALLOC_CTX *ctx = talloc_tos();
3368+ char *new_fs = NULL;
3369+ next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
3370+ ;
3371+ if (new_fs) {
3372+ client_set_fileselection(new_fs);
3373+ } else {
3374+ client_set_fileselection("");
3375+ }
3376+ return 0;
3377+}
3378+
3379+/****************************************************************************
3380+ Recursive file matching function act as find
3381+ match must be always set to true when calling this function
3382+****************************************************************************/
3383+
3384+static int file_find(struct file_list **list, const char *directory,
3385+ const char *expression, bool match)
3386+{
3387+ SMB_STRUCT_DIR *dir;
3388+ struct file_list *entry;
3389+ struct stat statbuf;
3390+ int ret;
3391+ char *path;
3392+ bool isdir;
3393+ const char *dname;
3394+
3395+ dir = sys_opendir(directory);
3396+ if (!dir)
3397+ return -1;
3398+
3399+ while ((dname = readdirname(dir))) {
3400+ if (!strcmp("..", dname))
3401+ continue;
3402+ if (!strcmp(".", dname))
3403+ continue;
3404+
3405+ if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
3406+ continue;
3407+ }
3408+
3409+ isdir = false;
3410+ if (!match || !gen_fnmatch(expression, dname)) {
3411+ if (recurse) {
3412+ ret = stat(path, &statbuf);
3413+ if (ret == 0) {
3414+ if (S_ISDIR(statbuf.st_mode)) {
3415+ isdir = true;
3416+ ret = file_find(list, path, expression, false);
3417+ }
3418+ } else {
3419+ d_printf("file_find: cannot stat file %s\n", path);
3420+ }
3421+
3422+ if (ret == -1) {
3423+ SAFE_FREE(path);
3424+ sys_closedir(dir);
3425+ return -1;
3426+ }
3427+ }
3428+ entry = SMB_MALLOC_P(struct file_list);
3429+ if (!entry) {
3430+ d_printf("Out of memory in file_find\n");
3431+ sys_closedir(dir);
3432+ return -1;
3433+ }
3434+ entry->file_path = path;
3435+ entry->isdir = isdir;
3436+ DLIST_ADD(*list, entry);
3437+ } else {
3438+ SAFE_FREE(path);
3439+ }
3440+ }
3441+
3442+ sys_closedir(dir);
3443+ return 0;
3444+}
3445+
3446+/****************************************************************************
3447+ mput some files.
3448+****************************************************************************/
3449+
3450+static int cmd_mput(void)
3451+{
3452+ TALLOC_CTX *ctx = talloc_tos();
3453+ char *p = NULL;
3454+
3455+ while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
3456+ int ret;
3457+ struct file_list *temp_list;
3458+ char *quest, *lname, *rname;
3459+
3460+ file_list = NULL;
3461+
3462+ ret = file_find(&file_list, ".", p, true);
3463+ if (ret) {
3464+ free_file_list(file_list);
3465+ continue;
3466+ }
3467+
3468+ quest = NULL;
3469+ lname = NULL;
3470+ rname = NULL;
3471+
3472+ for (temp_list = file_list; temp_list;
3473+ temp_list = temp_list->next) {
3474+
3475+ SAFE_FREE(lname);
3476+ if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
3477+ continue;
3478+ }
3479+ trim_string(lname, "./", "/");
3480+
3481+ /* check if it's a directory */
3482+ if (temp_list->isdir) {
3483+ /* if (!recurse) continue; */
3484+
3485+ SAFE_FREE(quest);
3486+ if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
3487+ break;
3488+ }
3489+ if (prompt && !yesno(quest)) { /* No */
3490+ /* Skip the directory */
3491+ lname[strlen(lname)-1] = '/';
3492+ if (!seek_list(temp_list, lname))
3493+ break;
3494+ } else { /* Yes */
3495+ SAFE_FREE(rname);
3496+ if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
3497+ break;
3498+ }
3499+ normalize_name(rname);
3500+ if (!cli_chkpath(cli, rname) &&
3501+ !do_mkdir(rname)) {
3502+ DEBUG (0, ("Unable to make dir, skipping..."));
3503+ /* Skip the directory */
3504+ lname[strlen(lname)-1] = '/';
3505+ if (!seek_list(temp_list, lname)) {
3506+ break;
3507+ }
3508+ }
3509+ }
3510+ continue;
3511+ } else {
3512+ SAFE_FREE(quest);
3513+ if (asprintf(&quest,"Put file %s? ", lname) < 0) {
3514+ break;
3515+ }
3516+ if (prompt && !yesno(quest)) {
3517+ /* No */
3518+ continue;
3519+ }
3520+
3521+ /* Yes */
3522+ SAFE_FREE(rname);
3523+ if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
3524+ break;
3525+ }
3526+ }
3527+
3528+ normalize_name(rname);
3529+
3530+ do_put(rname, lname, false);
3531+ }
3532+ free_file_list(file_list);
3533+ SAFE_FREE(quest);
3534+ SAFE_FREE(lname);
3535+ SAFE_FREE(rname);
3536+ }
3537+
3538+ return 0;
3539+}
3540+
3541+/****************************************************************************
3542+ Cancel a print job.
3543+****************************************************************************/
3544+
3545+static int do_cancel(int job)
3546+{
3547+ if (cli_printjob_del(cli, job)) {
3548+ d_printf("Job %d cancelled\n",job);
3549+ return 0;
3550+ } else {
3551+ d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
3552+ return 1;
3553+ }
3554+}
3555+
3556+/****************************************************************************
3557+ Cancel a print job.
3558+****************************************************************************/
3559+
3560+static int cmd_cancel(void)
3561+{
3562+ TALLOC_CTX *ctx = talloc_tos();
3563+ char *buf = NULL;
3564+ int job;
3565+
3566+ if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
3567+ d_printf("cancel <jobid> ...\n");
3568+ return 1;
3569+ }
3570+ do {
3571+ job = atoi(buf);
3572+ do_cancel(job);
3573+ } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
3574+
3575+ return 0;
3576+}
3577+
3578+/****************************************************************************
3579+ Print a file.
3580+****************************************************************************/
3581+
3582+static int cmd_print(void)
3583+{
3584+ TALLOC_CTX *ctx = talloc_tos();
3585+ char *lname = NULL;
3586+ char *rname = NULL;
3587+ char *p = NULL;
3588+
3589+ if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
3590+ d_printf("print <filename>\n");
3591+ return 1;
3592+ }
3593+
3594+ rname = talloc_strdup(ctx, lname);
3595+ if (!rname) {
3596+ return 1;
3597+ }
3598+ p = strrchr_m(rname,'/');
3599+ if (p) {
3600+ rname = talloc_asprintf(ctx,
3601+ "%s-%d",
3602+ p+1,
3603+ (int)sys_getpid());
3604+ }
3605+ if (strequal(lname,"-")) {
3606+ rname = talloc_asprintf(ctx,
3607+ "stdin-%d",
3608+ (int)sys_getpid());
3609+ }
3610+ if (!rname) {
3611+ return 1;
3612+ }
3613+
3614+ return do_put(rname, lname, false);
3615+}
3616+
3617+/****************************************************************************
3618+ Show a print queue entry.
3619+****************************************************************************/
3620+
3621+static void queue_fn(struct print_job_info *p)
3622+{
3623+ d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
3624+}
3625+
3626+/****************************************************************************
3627+ Show a print queue.
3628+****************************************************************************/
3629+
3630+static int cmd_queue(void)
3631+{
3632+ cli_print_queue(cli, queue_fn);
3633+ return 0;
3634+}
3635+
3636+/****************************************************************************
3637+ Delete some files.
3638+****************************************************************************/
3639+
3640+static void do_del(file_info *finfo, const char *dir)
3641+{
3642+ TALLOC_CTX *ctx = talloc_tos();
3643+ char *mask = NULL;
3644+
3645+ mask = talloc_asprintf(ctx,
3646+ "%s%c%s",
3647+ dir,
3648+ CLI_DIRSEP_CHAR,
3649+ finfo->name);
3650+ if (!mask) {
3651+ return;
3652+ }
3653+
3654+ if (finfo->mode & aDIR) {
3655+ TALLOC_FREE(mask);
3656+ return;
3657+ }
3658+
3659+ if (!cli_unlink(finfo->cli, mask)) {
3660+ d_printf("%s deleting remote file %s\n",
3661+ cli_errstr(finfo->cli),mask);
3662+ }
3663+ TALLOC_FREE(mask);
3664+}
3665+
3666+/****************************************************************************
3667+ Delete some files.
3668+****************************************************************************/
3669+
3670+static int cmd_del(void)
3671+{
3672+ TALLOC_CTX *ctx = talloc_tos();
3673+ char *mask = NULL;
3674+ char *buf = NULL;
3675+ uint16 attribute = aSYSTEM | aHIDDEN;
3676+
3677+ if (recurse) {
3678+ attribute |= aDIR;
3679+ }
3680+
3681+ mask = talloc_strdup(ctx, client_get_cur_dir());
3682+ if (!mask) {
3683+ return 1;
3684+ }
3685+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3686+ d_printf("del <filename>\n");
3687+ return 1;
3688+ }
3689+ mask = talloc_asprintf_append(mask, "%s", buf);
3690+ if (!mask) {
3691+ return 1;
3692+ }
3693+
3694+ do_list(mask,attribute,do_del,false,false);
3695+ return 0;
3696+}
3697+
3698+/****************************************************************************
3699+ Wildcard delete some files.
3700+****************************************************************************/
3701+
3702+static int cmd_wdel(void)
3703+{
3704+ TALLOC_CTX *ctx = talloc_tos();
3705+ char *mask = NULL;
3706+ char *buf = NULL;
3707+ uint16 attribute;
3708+ struct cli_state *targetcli;
3709+ char *targetname = NULL;
3710+
3711+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3712+ d_printf("wdel 0x<attrib> <wcard>\n");
3713+ return 1;
3714+ }
3715+
3716+ attribute = (uint16)strtol(buf, (char **)NULL, 16);
3717+
3718+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3719+ d_printf("wdel 0x<attrib> <wcard>\n");
3720+ return 1;
3721+ }
3722+
3723+ mask = talloc_asprintf(ctx, "%s%s",
3724+ client_get_cur_dir(),
3725+ buf);
3726+ if (!mask) {
3727+ return 1;
3728+ }
3729+
3730+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3731+ d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
3732+ return 1;
3733+ }
3734+
3735+ if (!cli_unlink_full(targetcli, targetname, attribute)) {
3736+ d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
3737+ }
3738+ return 0;
3739+}
3740+
3741+/****************************************************************************
3742+****************************************************************************/
3743+
3744+static int cmd_open(void)
3745+{
3746+ TALLOC_CTX *ctx = talloc_tos();
3747+ char *mask = NULL;
3748+ char *buf = NULL;
3749+ char *targetname = NULL;
3750+ struct cli_state *targetcli;
3751+ int fnum;
3752+
3753+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3754+ d_printf("open <filename>\n");
3755+ return 1;
3756+ }
3757+ mask = talloc_asprintf(ctx,
3758+ "%s%s",
3759+ client_get_cur_dir(),
3760+ buf);
3761+ if (!mask) {
3762+ return 1;
3763+ }
3764+
3765+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3766+ d_printf("open %s: %s\n", mask, cli_errstr(cli));
3767+ return 1;
3768+ }
3769+
3770+ fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
3771+ if (fnum == -1) {
3772+ fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
3773+ if (fnum != -1) {
3774+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
3775+ } else {
3776+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
3777+ }
3778+ } else {
3779+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
3780+ }
3781+ return 0;
3782+}
3783+
3784+static int cmd_posix_encrypt(void)
3785+{
3786+ TALLOC_CTX *ctx = talloc_tos();
3787+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3788+
3789+ if (cli->use_kerberos) {
3790+ status = cli_gss_smb_encryption_start(cli);
3791+ } else {
3792+ char *domain = NULL;
3793+ char *user = NULL;
3794+ char *password = NULL;
3795+
3796+ if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
3797+ d_printf("posix_encrypt domain user password\n");
3798+ return 1;
3799+ }
3800+
3801+ if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
3802+ d_printf("posix_encrypt domain user password\n");
3803+ return 1;
3804+ }
3805+
3806+ if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
3807+ d_printf("posix_encrypt domain user password\n");
3808+ return 1;
3809+ }
3810+
3811+ status = cli_raw_ntlm_smb_encryption_start(cli,
3812+ user,
3813+ password,
3814+ domain);
3815+ }
3816+
3817+ if (!NT_STATUS_IS_OK(status)) {
3818+ d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
3819+ } else {
3820+ d_printf("encryption on\n");
3821+ smb_encrypt = true;
3822+ }
3823+
3824+ return 0;
3825+}
3826+
3827+/****************************************************************************
3828+****************************************************************************/
3829+
3830+static int cmd_posix_open(void)
3831+{
3832+ TALLOC_CTX *ctx = talloc_tos();
3833+ char *mask = NULL;
3834+ char *buf = NULL;
3835+ char *targetname = NULL;
3836+ struct cli_state *targetcli;
3837+ mode_t mode;
3838+ int fnum;
3839+
3840+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3841+ d_printf("posix_open <filename> 0<mode>\n");
3842+ return 1;
3843+ }
3844+ mask = talloc_asprintf(ctx,
3845+ "%s%s",
3846+ client_get_cur_dir(),
3847+ buf);
3848+ if (!mask) {
3849+ return 1;
3850+ }
3851+
3852+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3853+ d_printf("posix_open <filename> 0<mode>\n");
3854+ return 1;
3855+ }
3856+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
3857+
3858+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3859+ d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
3860+ return 1;
3861+ }
3862+
3863+ fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
3864+ if (fnum == -1) {
3865+ fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
3866+ if (fnum != -1) {
3867+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
3868+ } else {
3869+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
3870+ }
3871+ } else {
3872+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
3873+ }
3874+
3875+ return 0;
3876+}
3877+
3878+static int cmd_posix_mkdir(void)
3879+{
3880+ TALLOC_CTX *ctx = talloc_tos();
3881+ char *mask = NULL;
3882+ char *buf = NULL;
3883+ char *targetname = NULL;
3884+ struct cli_state *targetcli;
3885+ mode_t mode;
3886+ int fnum;
3887+
3888+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3889+ d_printf("posix_mkdir <filename> 0<mode>\n");
3890+ return 1;
3891+ }
3892+ mask = talloc_asprintf(ctx,
3893+ "%s%s",
3894+ client_get_cur_dir(),
3895+ buf);
3896+ if (!mask) {
3897+ return 1;
3898+ }
3899+
3900+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3901+ d_printf("posix_mkdir <filename> 0<mode>\n");
3902+ return 1;
3903+ }
3904+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
3905+
3906+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3907+ d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
3908+ return 1;
3909+ }
3910+
3911+ fnum = cli_posix_mkdir(targetcli, targetname, mode);
3912+ if (fnum == -1) {
3913+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
3914+ } else {
3915+ d_printf("posix_mkdir created directory %s\n", targetname);
3916+ }
3917+ return 0;
3918+}
3919+
3920+static int cmd_posix_unlink(void)
3921+{
3922+ TALLOC_CTX *ctx = talloc_tos();
3923+ char *mask = NULL;
3924+ char *buf = NULL;
3925+ char *targetname = NULL;
3926+ struct cli_state *targetcli;
3927+
3928+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3929+ d_printf("posix_unlink <filename>\n");
3930+ return 1;
3931+ }
3932+ mask = talloc_asprintf(ctx,
3933+ "%s%s",
3934+ client_get_cur_dir(),
3935+ buf);
3936+ if (!mask) {
3937+ return 1;
3938+ }
3939+
3940+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3941+ d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
3942+ return 1;
3943+ }
3944+
3945+ if (!cli_posix_unlink(targetcli, targetname)) {
3946+ d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
3947+ } else {
3948+ d_printf("posix_unlink deleted file %s\n", targetname);
3949+ }
3950+
3951+ return 0;
3952+}
3953+
3954+static int cmd_posix_rmdir(void)
3955+{
3956+ TALLOC_CTX *ctx = talloc_tos();
3957+ char *mask = NULL;
3958+ char *buf = NULL;
3959+ char *targetname = NULL;
3960+ struct cli_state *targetcli;
3961+
3962+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3963+ d_printf("posix_rmdir <filename>\n");
3964+ return 1;
3965+ }
3966+ mask = talloc_asprintf(ctx,
3967+ "%s%s",
3968+ client_get_cur_dir(),
3969+ buf);
3970+ if (!mask) {
3971+ return 1;
3972+ }
3973+
3974+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3975+ d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
3976+ return 1;
3977+ }
3978+
3979+ if (!cli_posix_rmdir(targetcli, targetname)) {
3980+ d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
3981+ } else {
3982+ d_printf("posix_rmdir deleted directory %s\n", targetname);
3983+ }
3984+
3985+ return 0;
3986+}
3987+
3988+static int cmd_close(void)
3989+{
3990+ TALLOC_CTX *ctx = talloc_tos();
3991+ char *buf = NULL;
3992+ int fnum;
3993+
3994+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3995+ d_printf("close <fnum>\n");
3996+ return 1;
3997+ }
3998+
3999+ fnum = atoi(buf);
4000+ /* We really should use the targetcli here.... */
4001+ if (!cli_close(cli, fnum)) {
4002+ d_printf("close %d: %s\n", fnum, cli_errstr(cli));
4003+ return 1;
4004+ }
4005+ return 0;
4006+}
4007+
4008+static int cmd_posix(void)
4009+{
4010+ TALLOC_CTX *ctx = talloc_tos();
4011+ uint16 major, minor;
4012+ uint32 caplow, caphigh;
4013+ char *caps;
4014+
4015+ if (!SERVER_HAS_UNIX_CIFS(cli)) {
4016+ d_printf("Server doesn't support UNIX CIFS extensions.\n");
4017+ return 1;
4018+ }
4019+
4020+ if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
4021+ d_printf("Can't get UNIX CIFS extensions version from server.\n");
4022+ return 1;
4023+ }
4024+
4025+ d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
4026+
4027+ caps = talloc_strdup(ctx, "");
4028+ if (!caps) {
4029+ return 1;
4030+ }
4031+ if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
4032+ caps = talloc_asprintf_append(caps, "locks ");
4033+ if (!caps) {
4034+ return 1;
4035+ }
4036+ }
4037+ if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
4038+ caps = talloc_asprintf_append(caps, "acls ");
4039+ if (!caps) {
4040+ return 1;
4041+ }
4042+ }
4043+ if (caplow & CIFS_UNIX_XATTTR_CAP) {
4044+ caps = talloc_asprintf_append(caps, "eas ");
4045+ if (!caps) {
4046+ return 1;
4047+ }
4048+ }
4049+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
4050+ caps = talloc_asprintf_append(caps, "pathnames ");
4051+ if (!caps) {
4052+ return 1;
4053+ }
4054+ }
4055+ if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
4056+ caps = talloc_asprintf_append(caps, "posix_path_operations ");
4057+ if (!caps) {
4058+ return 1;
4059+ }
4060+ }
4061+ if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
4062+ caps = talloc_asprintf_append(caps, "large_read ");
4063+ if (!caps) {
4064+ return 1;
4065+ }
4066+ }
4067+ if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
4068+ caps = talloc_asprintf_append(caps, "large_write ");
4069+ if (!caps) {
4070+ return 1;
4071+ }
4072+ }
4073+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
4074+ caps = talloc_asprintf_append(caps, "posix_encrypt ");
4075+ if (!caps) {
4076+ return 1;
4077+ }
4078+ }
4079+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
4080+ caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
4081+ if (!caps) {
4082+ return 1;
4083+ }
4084+ }
4085+
4086+ if (*caps && caps[strlen(caps)-1] == ' ') {
4087+ caps[strlen(caps)-1] = '\0';
4088+ }
4089+
4090+ d_printf("Server supports CIFS capabilities %s\n", caps);
4091+
4092+ if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
4093+ d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
4094+ return 1;
4095+ }
4096+
4097+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
4098+ CLI_DIRSEP_CHAR = '/';
4099+ *CLI_DIRSEP_STR = '/';
4100+ client_set_cur_dir(CLI_DIRSEP_STR);
4101+ }
4102+
4103+ return 0;
4104+}
4105+
4106+static int cmd_lock(void)
4107+{
4108+ TALLOC_CTX *ctx = talloc_tos();
4109+ char *buf = NULL;
4110+ uint64_t start, len;
4111+ enum brl_type lock_type;
4112+ int fnum;
4113+
4114+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4115+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4116+ return 1;
4117+ }
4118+ fnum = atoi(buf);
4119+
4120+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4121+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4122+ return 1;
4123+ }
4124+
4125+ if (*buf == 'r' || *buf == 'R') {
4126+ lock_type = READ_LOCK;
4127+ } else if (*buf == 'w' || *buf == 'W') {
4128+ lock_type = WRITE_LOCK;
4129+ } else {
4130+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4131+ return 1;
4132+ }
4133+
4134+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4135+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4136+ return 1;
4137+ }
4138+
4139+ start = (uint64_t)strtol(buf, (char **)NULL, 16);
4140+
4141+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4142+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4143+ return 1;
4144+ }
4145+
4146+ len = (uint64_t)strtol(buf, (char **)NULL, 16);
4147+
4148+ if (!cli_posix_lock(cli, fnum, start, len, true, lock_type)) {
4149+ d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
4150+ }
4151+
4152+ return 0;
4153+}
4154+
4155+static int cmd_unlock(void)
4156+{
4157+ TALLOC_CTX *ctx = talloc_tos();
4158+ char *buf = NULL;
4159+ uint64_t start, len;
4160+ int fnum;
4161+
4162+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4163+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4164+ return 1;
4165+ }
4166+ fnum = atoi(buf);
4167+
4168+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4169+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4170+ return 1;
4171+ }
4172+
4173+ start = (uint64_t)strtol(buf, (char **)NULL, 16);
4174+
4175+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4176+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4177+ return 1;
4178+ }
4179+
4180+ len = (uint64_t)strtol(buf, (char **)NULL, 16);
4181+
4182+ if (!cli_posix_unlock(cli, fnum, start, len)) {
4183+ d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
4184+ }
4185+
4186+ return 0;
4187+}
4188+
4189+
4190+/****************************************************************************
4191+ Remove a directory.
4192+****************************************************************************/
4193+
4194+static int cmd_rmdir(void)
4195+{
4196+ TALLOC_CTX *ctx = talloc_tos();
4197+ char *mask = NULL;
4198+ char *buf = NULL;
4199+ char *targetname = NULL;
4200+ struct cli_state *targetcli;
4201+
4202+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4203+ d_printf("rmdir <dirname>\n");
4204+ return 1;
4205+ }
4206+ mask = talloc_asprintf(ctx,
4207+ "%s%s",
4208+ client_get_cur_dir(),
4209+ buf);
4210+ if (!mask) {
4211+ return 1;
4212+ }
4213+
4214+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4215+ d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
4216+ return 1;
4217+ }
4218+
4219+ if (!cli_rmdir(targetcli, targetname)) {
4220+ d_printf("%s removing remote directory file %s\n",
4221+ cli_errstr(targetcli),mask);
4222+ }
4223+
4224+ return 0;
4225+}
4226+
4227+/****************************************************************************
4228+ UNIX hardlink.
4229+****************************************************************************/
4230+
4231+static int cmd_link(void)
4232+{
4233+ TALLOC_CTX *ctx = talloc_tos();
4234+ char *oldname = NULL;
4235+ char *newname = NULL;
4236+ char *buf = NULL;
4237+ char *buf2 = NULL;
4238+ char *targetname = NULL;
4239+ struct cli_state *targetcli;
4240+
4241+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4242+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4243+ d_printf("link <oldname> <newname>\n");
4244+ return 1;
4245+ }
4246+ oldname = talloc_asprintf(ctx,
4247+ "%s%s",
4248+ client_get_cur_dir(),
4249+ buf);
4250+ if (!oldname) {
4251+ return 1;
4252+ }
4253+ newname = talloc_asprintf(ctx,
4254+ "%s%s",
4255+ client_get_cur_dir(),
4256+ buf2);
4257+ if (!newname) {
4258+ return 1;
4259+ }
4260+
4261+ if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
4262+ d_printf("link %s: %s\n", oldname, cli_errstr(cli));
4263+ return 1;
4264+ }
4265+
4266+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4267+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4268+ return 1;
4269+ }
4270+
4271+ if (!cli_unix_hardlink(targetcli, targetname, newname)) {
4272+ d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
4273+ return 1;
4274+ }
4275+ return 0;
4276+}
4277+
4278+/****************************************************************************
4279+ UNIX symlink.
4280+****************************************************************************/
4281+
4282+static int cmd_symlink(void)
4283+{
4284+ TALLOC_CTX *ctx = talloc_tos();
4285+ char *oldname = NULL;
4286+ char *newname = NULL;
4287+ char *buf = NULL;
4288+ char *buf2 = NULL;
4289+ char *targetname = NULL;
4290+ struct cli_state *targetcli;
4291+
4292+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4293+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4294+ d_printf("symlink <oldname> <newname>\n");
4295+ return 1;
4296+ }
4297+ oldname = talloc_asprintf(ctx,
4298+ "%s%s",
4299+ client_get_cur_dir(),
4300+ buf);
4301+ if (!oldname) {
4302+ return 1;
4303+ }
4304+ newname = talloc_asprintf(ctx,
4305+ "%s%s",
4306+ client_get_cur_dir(),
4307+ buf2);
4308+ if (!newname) {
4309+ return 1;
4310+ }
4311+
4312+ if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
4313+ d_printf("link %s: %s\n", oldname, cli_errstr(cli));
4314+ return 1;
4315+ }
4316+
4317+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4318+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4319+ return 1;
4320+ }
4321+
4322+ if (!cli_unix_symlink(targetcli, targetname, newname)) {
4323+ d_printf("%s symlinking files (%s -> %s)\n",
4324+ cli_errstr(targetcli), newname, targetname);
4325+ return 1;
4326+ }
4327+
4328+ return 0;
4329+}
4330+
4331+/****************************************************************************
4332+ UNIX chmod.
4333+****************************************************************************/
4334+
4335+static int cmd_chmod(void)
4336+{
4337+ TALLOC_CTX *ctx = talloc_tos();
4338+ char *src = NULL;
4339+ char *buf = NULL;
4340+ char *buf2 = NULL;
4341+ char *targetname = NULL;
4342+ struct cli_state *targetcli;
4343+ mode_t mode;
4344+
4345+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4346+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4347+ d_printf("chmod mode file\n");
4348+ return 1;
4349+ }
4350+ src = talloc_asprintf(ctx,
4351+ "%s%s",
4352+ client_get_cur_dir(),
4353+ buf2);
4354+ if (!src) {
4355+ return 1;
4356+ }
4357+
4358+ mode = (mode_t)strtol(buf, NULL, 8);
4359+
4360+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
4361+ d_printf("chmod %s: %s\n", src, cli_errstr(cli));
4362+ return 1;
4363+ }
4364+
4365+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4366+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4367+ return 1;
4368+ }
4369+
4370+ if (!cli_unix_chmod(targetcli, targetname, mode)) {
4371+ d_printf("%s chmod file %s 0%o\n",
4372+ cli_errstr(targetcli), src, (unsigned int)mode);
4373+ return 1;
4374+ }
4375+
4376+ return 0;
4377+}
4378+
4379+static const char *filetype_to_str(mode_t mode)
4380+{
4381+ if (S_ISREG(mode)) {
4382+ return "regular file";
4383+ } else if (S_ISDIR(mode)) {
4384+ return "directory";
4385+ } else
4386+#ifdef S_ISCHR
4387+ if (S_ISCHR(mode)) {
4388+ return "character device";
4389+ } else
4390+#endif
4391+#ifdef S_ISBLK
4392+ if (S_ISBLK(mode)) {
4393+ return "block device";
4394+ } else
4395+#endif
4396+#ifdef S_ISFIFO
4397+ if (S_ISFIFO(mode)) {
4398+ return "fifo";
4399+ } else
4400+#endif
4401+#ifdef S_ISLNK
4402+ if (S_ISLNK(mode)) {
4403+ return "symbolic link";
4404+ } else
4405+#endif
4406+#ifdef S_ISSOCK
4407+ if (S_ISSOCK(mode)) {
4408+ return "socket";
4409+ } else
4410+#endif
4411+ return "";
4412+}
4413+
4414+static char rwx_to_str(mode_t m, mode_t bt, char ret)
4415+{
4416+ if (m & bt) {
4417+ return ret;
4418+ } else {
4419+ return '-';
4420+ }
4421+}
4422+
4423+static char *unix_mode_to_str(char *s, mode_t m)
4424+{
4425+ char *p = s;
4426+ const char *str = filetype_to_str(m);
4427+
4428+ switch(str[0]) {
4429+ case 'd':
4430+ *p++ = 'd';
4431+ break;
4432+ case 'c':
4433+ *p++ = 'c';
4434+ break;
4435+ case 'b':
4436+ *p++ = 'b';
4437+ break;
4438+ case 'f':
4439+ *p++ = 'p';
4440+ break;
4441+ case 's':
4442+ *p++ = str[1] == 'y' ? 'l' : 's';
4443+ break;
4444+ case 'r':
4445+ default:
4446+ *p++ = '-';
4447+ break;
4448+ }
4449+ *p++ = rwx_to_str(m, S_IRUSR, 'r');
4450+ *p++ = rwx_to_str(m, S_IWUSR, 'w');
4451+ *p++ = rwx_to_str(m, S_IXUSR, 'x');
4452+ *p++ = rwx_to_str(m, S_IRGRP, 'r');
4453+ *p++ = rwx_to_str(m, S_IWGRP, 'w');
4454+ *p++ = rwx_to_str(m, S_IXGRP, 'x');
4455+ *p++ = rwx_to_str(m, S_IROTH, 'r');
4456+ *p++ = rwx_to_str(m, S_IWOTH, 'w');
4457+ *p++ = rwx_to_str(m, S_IXOTH, 'x');
4458+ *p++ = '\0';
4459+ return s;
4460+}
4461+
4462+/****************************************************************************
4463+ Utility function for UNIX getfacl.
4464+****************************************************************************/
4465+
4466+static char *perms_to_string(fstring permstr, unsigned char perms)
4467+{
4468+ fstrcpy(permstr, "---");
4469+ if (perms & SMB_POSIX_ACL_READ) {
4470+ permstr[0] = 'r';
4471+ }
4472+ if (perms & SMB_POSIX_ACL_WRITE) {
4473+ permstr[1] = 'w';
4474+ }
4475+ if (perms & SMB_POSIX_ACL_EXECUTE) {
4476+ permstr[2] = 'x';
4477+ }
4478+ return permstr;
4479+}
4480+
4481+/****************************************************************************
4482+ UNIX getfacl.
4483+****************************************************************************/
4484+
4485+static int cmd_getfacl(void)
4486+{
4487+ TALLOC_CTX *ctx = talloc_tos();
4488+ char *src = NULL;
4489+ char *name = NULL;
4490+ char *targetname = NULL;
4491+ struct cli_state *targetcli;
4492+ uint16 major, minor;
4493+ uint32 caplow, caphigh;
4494+ char *retbuf = NULL;
4495+ size_t rb_size = 0;
4496+ SMB_STRUCT_STAT sbuf;
4497+ uint16 num_file_acls = 0;
4498+ uint16 num_dir_acls = 0;
4499+ uint16 i;
4500+
4501+ if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4502+ d_printf("getfacl filename\n");
4503+ return 1;
4504+ }
4505+ src = talloc_asprintf(ctx,
4506+ "%s%s",
4507+ client_get_cur_dir(),
4508+ name);
4509+ if (!src) {
4510+ return 1;
4511+ }
4512+
4513+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
4514+ d_printf("stat %s: %s\n", src, cli_errstr(cli));
4515+ return 1;
4516+ }
4517+
4518+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4519+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4520+ return 1;
4521+ }
4522+
4523+ if (!cli_unix_extensions_version(targetcli, &major, &minor,
4524+ &caplow, &caphigh)) {
4525+ d_printf("Can't get UNIX CIFS version from server.\n");
4526+ return 1;
4527+ }
4528+
4529+ if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
4530+ d_printf("This server supports UNIX extensions "
4531+ "but doesn't support POSIX ACLs.\n");
4532+ return 1;
4533+ }
4534+
4535+ if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
4536+ d_printf("%s getfacl doing a stat on file %s\n",
4537+ cli_errstr(targetcli), src);
4538+ return 1;
4539+ }
4540+
4541+ if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
4542+ d_printf("%s getfacl file %s\n",
4543+ cli_errstr(targetcli), src);
4544+ return 1;
4545+ }
4546+
4547+ /* ToDo : Print out the ACL values. */
4548+ if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
4549+ d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
4550+ src, (unsigned int)CVAL(retbuf,0) );
4551+ SAFE_FREE(retbuf);
4552+ return 1;
4553+ }
4554+
4555+ num_file_acls = SVAL(retbuf,2);
4556+ num_dir_acls = SVAL(retbuf,4);
4557+ if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
4558+ d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
4559+ src,
4560+ (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
4561+ (unsigned int)rb_size);
4562+
4563+ SAFE_FREE(retbuf);
4564+ return 1;
4565+ }
4566+
4567+ d_printf("# file: %s\n", src);
4568+ d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
4569+
4570+ if (num_file_acls == 0 && num_dir_acls == 0) {
4571+ d_printf("No acls found.\n");
4572+ }
4573+
4574+ for (i = 0; i < num_file_acls; i++) {
4575+ uint32 uorg;
4576+ fstring permstring;
4577+ unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
4578+ unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
4579+
4580+ switch(tagtype) {
4581+ case SMB_POSIX_ACL_USER_OBJ:
4582+ d_printf("user::");
4583+ break;
4584+ case SMB_POSIX_ACL_USER:
4585+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4586+ d_printf("user:%u:", uorg);
4587+ break;
4588+ case SMB_POSIX_ACL_GROUP_OBJ:
4589+ d_printf("group::");
4590+ break;
4591+ case SMB_POSIX_ACL_GROUP:
4592+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4593+ d_printf("group:%u:", uorg);
4594+ break;
4595+ case SMB_POSIX_ACL_MASK:
4596+ d_printf("mask::");
4597+ break;
4598+ case SMB_POSIX_ACL_OTHER:
4599+ d_printf("other::");
4600+ break;
4601+ default:
4602+ d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
4603+ src, (unsigned int)tagtype );
4604+ SAFE_FREE(retbuf);
4605+ return 1;
4606+ }
4607+
4608+ d_printf("%s\n", perms_to_string(permstring, perms));
4609+ }
4610+
4611+ for (i = 0; i < num_dir_acls; i++) {
4612+ uint32 uorg;
4613+ fstring permstring;
4614+ unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
4615+ unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
4616+
4617+ switch(tagtype) {
4618+ case SMB_POSIX_ACL_USER_OBJ:
4619+ d_printf("default:user::");
4620+ break;
4621+ case SMB_POSIX_ACL_USER:
4622+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4623+ d_printf("default:user:%u:", uorg);
4624+ break;
4625+ case SMB_POSIX_ACL_GROUP_OBJ:
4626+ d_printf("default:group::");
4627+ break;
4628+ case SMB_POSIX_ACL_GROUP:
4629+ uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4630+ d_printf("default:group:%u:", uorg);
4631+ break;
4632+ case SMB_POSIX_ACL_MASK:
4633+ d_printf("default:mask::");
4634+ break;
4635+ case SMB_POSIX_ACL_OTHER:
4636+ d_printf("default:other::");
4637+ break;
4638+ default:
4639+ d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
4640+ src, (unsigned int)tagtype );
4641+ SAFE_FREE(retbuf);
4642+ return 1;
4643+ }
4644+
4645+ d_printf("%s\n", perms_to_string(permstring, perms));
4646+ }
4647+
4648+ SAFE_FREE(retbuf);
4649+ return 0;
4650+}
4651+
4652+/****************************************************************************
4653+ UNIX stat.
4654+****************************************************************************/
4655+
4656+static int cmd_stat(void)
4657+{
4658+ TALLOC_CTX *ctx = talloc_tos();
4659+ char *src = NULL;
4660+ char *name = NULL;
4661+ char *targetname = NULL;
4662+ struct cli_state *targetcli;
4663+ fstring mode_str;
4664+ SMB_STRUCT_STAT sbuf;
4665+ struct tm *lt;
4666+
4667+ if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4668+ d_printf("stat file\n");
4669+ return 1;
4670+ }
4671+ src = talloc_asprintf(ctx,
4672+ "%s%s",
4673+ client_get_cur_dir(),
4674+ name);
4675+ if (!src) {
4676+ return 1;
4677+ }
4678+
4679+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
4680+ d_printf("stat %s: %s\n", src, cli_errstr(cli));
4681+ return 1;
4682+ }
4683+
4684+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4685+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4686+ return 1;
4687+ }
4688+
4689+ if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
4690+ d_printf("%s stat file %s\n",
4691+ cli_errstr(targetcli), src);
4692+ return 1;
4693+ }
4694+
4695+ /* Print out the stat values. */
4696+ d_printf("File: %s\n", src);
4697+ d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
4698+ (double)sbuf.st_size,
4699+ (unsigned int)sbuf.st_blocks,
4700+ filetype_to_str(sbuf.st_mode));
4701+
4702+#if defined(S_ISCHR) && defined(S_ISBLK)
4703+ if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
4704+ d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
4705+ (double)sbuf.st_ino,
4706+ (unsigned int)sbuf.st_nlink,
4707+ unix_dev_major(sbuf.st_rdev),
4708+ unix_dev_minor(sbuf.st_rdev));
4709+ } else
4710+#endif
4711+ d_printf("Inode: %.0f\tLinks: %u\n",
4712+ (double)sbuf.st_ino,
4713+ (unsigned int)sbuf.st_nlink);
4714+
4715+ d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
4716+ ((int)sbuf.st_mode & 0777),
4717+ unix_mode_to_str(mode_str, sbuf.st_mode),
4718+ (unsigned int)sbuf.st_uid,
4719+ (unsigned int)sbuf.st_gid);
4720+
4721+ lt = localtime(&sbuf.st_atime);
4722+ if (lt) {
4723+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4724+ } else {
4725+ fstrcpy(mode_str, "unknown");
4726+ }
4727+ d_printf("Access: %s\n", mode_str);
4728+
4729+ lt = localtime(&sbuf.st_mtime);
4730+ if (lt) {
4731+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4732+ } else {
4733+ fstrcpy(mode_str, "unknown");
4734+ }
4735+ d_printf("Modify: %s\n", mode_str);
4736+
4737+ lt = localtime(&sbuf.st_ctime);
4738+ if (lt) {
4739+ strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4740+ } else {
4741+ fstrcpy(mode_str, "unknown");
4742+ }
4743+ d_printf("Change: %s\n", mode_str);
4744+
4745+ return 0;
4746+}
4747+
4748+
4749+/****************************************************************************
4750+ UNIX chown.
4751+****************************************************************************/
4752+
4753+static int cmd_chown(void)
4754+{
4755+ TALLOC_CTX *ctx = talloc_tos();
4756+ char *src = NULL;
4757+ uid_t uid;
4758+ gid_t gid;
4759+ char *buf, *buf2, *buf3;
4760+ struct cli_state *targetcli;
4761+ char *targetname = NULL;
4762+
4763+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4764+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
4765+ !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
4766+ d_printf("chown uid gid file\n");
4767+ return 1;
4768+ }
4769+
4770+ uid = (uid_t)atoi(buf);
4771+ gid = (gid_t)atoi(buf2);
4772+
4773+ src = talloc_asprintf(ctx,
4774+ "%s%s",
4775+ client_get_cur_dir(),
4776+ buf3);
4777+ if (!src) {
4778+ return 1;
4779+ }
4780+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname) ) {
4781+ d_printf("chown %s: %s\n", src, cli_errstr(cli));
4782+ return 1;
4783+ }
4784+
4785+ if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4786+ d_printf("Server doesn't support UNIX CIFS calls.\n");
4787+ return 1;
4788+ }
4789+
4790+ if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
4791+ d_printf("%s chown file %s uid=%d, gid=%d\n",
4792+ cli_errstr(targetcli), src, (int)uid, (int)gid);
4793+ return 1;
4794+ }
4795+
4796+ return 0;
4797+}
4798+
4799+/****************************************************************************
4800+ Rename some file.
4801+****************************************************************************/
4802+
4803+static int cmd_rename(void)
4804+{
4805+ TALLOC_CTX *ctx = talloc_tos();
4806+ char *src, *dest;
4807+ char *buf, *buf2;
4808+ struct cli_state *targetcli;
4809+ char *targetsrc;
4810+ char *targetdest;
4811+
4812+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4813+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4814+ d_printf("rename <src> <dest>\n");
4815+ return 1;
4816+ }
4817+
4818+ src = talloc_asprintf(ctx,
4819+ "%s%s",
4820+ client_get_cur_dir(),
4821+ buf);
4822+ if (!src) {
4823+ return 1;
4824+ }
4825+
4826+ dest = talloc_asprintf(ctx,
4827+ "%s%s",
4828+ client_get_cur_dir(),
4829+ buf2);
4830+ if (!dest) {
4831+ return 1;
4832+ }
4833+
4834+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetsrc)) {
4835+ d_printf("rename %s: %s\n", src, cli_errstr(cli));
4836+ return 1;
4837+ }
4838+
4839+ if (!cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli, &targetdest)) {
4840+ d_printf("rename %s: %s\n", dest, cli_errstr(cli));
4841+ return 1;
4842+ }
4843+
4844+ if (!cli_rename(targetcli, targetsrc, targetdest)) {
4845+ d_printf("%s renaming files %s -> %s \n",
4846+ cli_errstr(targetcli),
4847+ targetsrc,
4848+ targetdest);
4849+ return 1;
4850+ }
4851+
4852+ return 0;
4853+}
4854+
4855+/****************************************************************************
4856+ Print the volume name.
4857+****************************************************************************/
4858+
4859+static int cmd_volume(void)
4860+{
4861+ fstring volname;
4862+ uint32 serial_num;
4863+ time_t create_date;
4864+
4865+ if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
4866+ d_printf("Errr %s getting volume info\n",cli_errstr(cli));
4867+ return 1;
4868+ }
4869+
4870+ d_printf("Volume: |%s| serial number 0x%x\n",
4871+ volname, (unsigned int)serial_num);
4872+ return 0;
4873+}
4874+
4875+/****************************************************************************
4876+ Hard link files using the NT call.
4877+****************************************************************************/
4878+
4879+static int cmd_hardlink(void)
4880+{
4881+ TALLOC_CTX *ctx = talloc_tos();
4882+ char *src, *dest;
4883+ char *buf, *buf2;
4884+ struct cli_state *targetcli;
4885+ char *targetname;
4886+
4887+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4888+ !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4889+ d_printf("hardlink <src> <dest>\n");
4890+ return 1;
4891+ }
4892+
4893+ src = talloc_asprintf(ctx,
4894+ "%s%s",
4895+ client_get_cur_dir(),
4896+ buf);
4897+ if (!src) {
4898+ return 1;
4899+ }
4900+
4901+ dest = talloc_asprintf(ctx,
4902+ "%s%s",
4903+ client_get_cur_dir(),
4904+ buf2);
4905+ if (!dest) {
4906+ return 1;
4907+ }
4908+
4909+ if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
4910+ d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
4911+ return 1;
4912+ }
4913+
4914+ if (!cli_nt_hardlink(targetcli, targetname, dest)) {
4915+ d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
4916+ return 1;
4917+ }
4918+
4919+ return 0;
4920+}
4921+
4922+/****************************************************************************
4923+ Toggle the prompt flag.
4924+****************************************************************************/
4925+
4926+static int cmd_prompt(void)
4927+{
4928+ prompt = !prompt;
4929+ DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
4930+ return 1;
4931+}
4932+
4933+/****************************************************************************
4934+ Set the newer than time.
4935+****************************************************************************/
4936+
4937+static int cmd_newer(void)
4938+{
4939+ TALLOC_CTX *ctx = talloc_tos();
4940+ char *buf;
4941+ bool ok;
4942+ SMB_STRUCT_STAT sbuf;
4943+
4944+ ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
4945+ if (ok && (sys_stat(buf,&sbuf) == 0)) {
4946+ newer_than = sbuf.st_mtime;
4947+ DEBUG(1,("Getting files newer than %s",
4948+ time_to_asc(newer_than)));
4949+ } else {
4950+ newer_than = 0;
4951+ }
4952+
4953+ if (ok && newer_than == 0) {
4954+ d_printf("Error setting newer-than time\n");
4955+ return 1;
4956+ }
4957+
4958+ return 0;
4959+}
4960+
4961+/****************************************************************************
4962+ Set the archive level.
4963+****************************************************************************/
4964+
4965+static int cmd_archive(void)
4966+{
4967+ TALLOC_CTX *ctx = talloc_tos();
4968+ char *buf;
4969+
4970+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4971+ archive_level = atoi(buf);
4972+ } else {
4973+ d_printf("Archive level is %d\n",archive_level);
4974+ }
4975+
4976+ return 0;
4977+}
4978+
4979+/****************************************************************************
4980+ Toggle the lowercaseflag.
4981+****************************************************************************/
4982+
4983+static int cmd_lowercase(void)
4984+{
4985+ lowercase = !lowercase;
4986+ DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
4987+ return 0;
4988+}
4989+
4990+/****************************************************************************
4991+ Toggle the case sensitive flag.
4992+****************************************************************************/
4993+
4994+static int cmd_setcase(void)
4995+{
4996+ bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
4997+
4998+ cli_set_case_sensitive(cli, !orig_case_sensitive);
4999+ DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
5000+ "on":"off"));
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: