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

Proposed by Stefano Rivera
Status: Merged
Merge reported by: Benjamin Drung
Merged at revision: not available
Proposed branch: lp:~stefanor/ubuntu/maverick/samba/ntlm-auth-623342
Merge into: lp:ubuntu/maverick-proposed/samba
Diff against target: 18873 lines (+18017/-338)
41 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/libwbclient/wbc_async.c (+774/-0)
.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c (+690/-0)
.pc/security-CVE-2011-0719.patch/source3/client/client.c (+5041/-0)
.pc/security-CVE-2011-0719.patch/source3/client/dnsbrowse.c (+237/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/events.c (+330/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/g_lock.c (+766/-0)
.pc/security-CVE-2011-0719.patch/source3/lib/packet.c (+273/-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 (+2012/-0)
.pc/security-CVE-2011-0719.patch/source3/libaddns/dnssock.c (+377/-0)
.pc/security-CVE-2011-0719.patch/source3/libsmb/nmblib.c (+1404/-0)
.pc/security-CVE-2011-0719.patch/source3/nmbd/nmbd_packets.c (+2119/-0)
.pc/security-CVE-2011-0719.patch/source3/utils/smbfilter.c (+295/-0)
.pc/security-CVE-2011-0719.patch/source3/winbindd/winbindd_dual.c (+1550/-0)
debian/changelog (+266/-316)
debian/control (+1/-1)
debian/patches/ntlm-auth-lp623342.patch (+64/-0)
debian/patches/security-CVE-2011-0719.patch (+436/-0)
debian/patches/series (+2/-0)
lib/tevent/tevent_select.c (+10/-0)
lib/tevent/tevent_standard.c (+5/-0)
nsswitch/libwbclient/wbc_async.c (+1/-1)
nsswitch/wb_common.c (+14/-0)
source3/client/client.c (+3/-1)
source3/client/dnsbrowse.c (+11/-0)
source3/lib/events.c (+8/-0)
source3/lib/g_lock.c (+3/-1)
source3/lib/packet.c (+5/-0)
source3/lib/readline.c (+5/-0)
source3/lib/select.c (+12/-0)
source3/lib/util_sock.c (+12/-3)
source3/libaddns/dnssock.c (+5/-0)
source3/libsmb/nmblib.c (+5/-0)
source3/nmbd/nmbd_packets.c (+31/-6)
source3/utils/smbfilter.c (+5/-2)
source3/winbindd/winbindd_cm.c (+13/-7)
source3/winbindd/winbindd_dual.c (+7/-0)
To merge this branch: bzr merge lp:~stefanor/ubuntu/maverick/samba/ntlm-auth-623342
Reviewer Review Type Date Requested Status
Ubuntu Development Team Pending
Review via email: mp+51559@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-12-17 10:40:10 +0000
3+++ .pc/applied-patches 2011-03-02 20:48:44 +0000
4@@ -14,3 +14,5 @@
5 security-CVE-2010-3069.patch
6 fix-lpbug-393012.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:48:44 +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:48:44 +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 directory '.pc/security-CVE-2011-0719.patch/nsswitch/libwbclient'
842=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c'
843--- .pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c 1970-01-01 00:00:00 +0000
844+++ .pc/security-CVE-2011-0719.patch/nsswitch/libwbclient/wbc_async.c 2011-03-02 20:48:44 +0000
845@@ -0,0 +1,774 @@
846+/*
847+ Unix SMB/CIFS implementation.
848+ Infrastructure for async winbind requests
849+ Copyright (C) Volker Lendecke 2008
850+
851+ ** NOTE! The following LGPL license applies to the wbclient
852+ ** library. This does NOT imply that all of Samba is released
853+ ** under the LGPL
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 "replace.h"
870+#include "system/filesys.h"
871+#include "system/network.h"
872+#include <talloc.h>
873+#include <tevent.h>
874+#include "lib/async_req/async_sock.h"
875+#include "nsswitch/winbind_struct_protocol.h"
876+#include "nsswitch/libwbclient/wbclient.h"
877+#include "nsswitch/libwbclient/wbc_async.h"
878+
879+wbcErr map_wbc_err_from_errno(int error)
880+{
881+ switch(error) {
882+ case EPERM:
883+ case EACCES:
884+ return WBC_ERR_AUTH_ERROR;
885+ case ENOMEM:
886+ return WBC_ERR_NO_MEMORY;
887+ case EIO:
888+ default:
889+ return WBC_ERR_UNKNOWN_FAILURE;
890+ }
891+}
892+
893+bool tevent_req_is_wbcerr(struct tevent_req *req, wbcErr *pwbc_err)
894+{
895+ enum tevent_req_state state;
896+ uint64_t error;
897+ if (!tevent_req_is_error(req, &state, &error)) {
898+ *pwbc_err = WBC_ERR_SUCCESS;
899+ return false;
900+ }
901+
902+ switch (state) {
903+ case TEVENT_REQ_USER_ERROR:
904+ *pwbc_err = error;
905+ break;
906+ case TEVENT_REQ_TIMED_OUT:
907+ *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
908+ break;
909+ case TEVENT_REQ_NO_MEMORY:
910+ *pwbc_err = WBC_ERR_NO_MEMORY;
911+ break;
912+ default:
913+ *pwbc_err = WBC_ERR_UNKNOWN_FAILURE;
914+ break;
915+ }
916+ return true;
917+}
918+
919+wbcErr tevent_req_simple_recv_wbcerr(struct tevent_req *req)
920+{
921+ wbcErr wbc_err;
922+
923+ if (tevent_req_is_wbcerr(req, &wbc_err)) {
924+ return wbc_err;
925+ }
926+
927+ return WBC_ERR_SUCCESS;
928+}
929+
930+struct wbc_debug_ops {
931+ void (*debug)(void *context, enum wbcDebugLevel level,
932+ const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
933+ void *context;
934+};
935+
936+struct wb_context {
937+ struct tevent_queue *queue;
938+ int fd;
939+ bool is_priv;
940+ const char *dir;
941+ struct wbc_debug_ops debug_ops;
942+};
943+
944+static int make_nonstd_fd(int fd)
945+{
946+ int i;
947+ int sys_errno = 0;
948+ int fds[3];
949+ int num_fds = 0;
950+
951+ if (fd == -1) {
952+ return -1;
953+ }
954+ while (fd < 3) {
955+ fds[num_fds++] = fd;
956+ fd = dup(fd);
957+ if (fd == -1) {
958+ sys_errno = errno;
959+ break;
960+ }
961+ }
962+ for (i=0; i<num_fds; i++) {
963+ close(fds[i]);
964+ }
965+ if (fd == -1) {
966+ errno = sys_errno;
967+ }
968+ return fd;
969+}
970+
971+/****************************************************************************
972+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
973+ else
974+ if SYSV use O_NDELAY
975+ if BSD use FNDELAY
976+ Set close on exec also.
977+****************************************************************************/
978+
979+static int make_safe_fd(int fd)
980+{
981+ int result, flags;
982+ int new_fd = make_nonstd_fd(fd);
983+
984+ if (new_fd == -1) {
985+ goto fail;
986+ }
987+
988+ /* Socket should be nonblocking. */
989+
990+#ifdef O_NONBLOCK
991+#define FLAG_TO_SET O_NONBLOCK
992+#else
993+#ifdef SYSV
994+#define FLAG_TO_SET O_NDELAY
995+#else /* BSD */
996+#define FLAG_TO_SET FNDELAY
997+#endif
998+#endif
999+
1000+ if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
1001+ goto fail;
1002+ }
1003+
1004+ flags |= FLAG_TO_SET;
1005+ if (fcntl(new_fd, F_SETFL, flags) == -1) {
1006+ goto fail;
1007+ }
1008+
1009+#undef FLAG_TO_SET
1010+
1011+ /* Socket should be closed on exec() */
1012+#ifdef FD_CLOEXEC
1013+ result = flags = fcntl(new_fd, F_GETFD, 0);
1014+ if (flags >= 0) {
1015+ flags |= FD_CLOEXEC;
1016+ result = fcntl( new_fd, F_SETFD, flags );
1017+ }
1018+ if (result < 0) {
1019+ goto fail;
1020+ }
1021+#endif
1022+ return new_fd;
1023+
1024+ fail:
1025+ if (new_fd != -1) {
1026+ int sys_errno = errno;
1027+ close(new_fd);
1028+ errno = sys_errno;
1029+ }
1030+ return -1;
1031+}
1032+
1033+/* Just put a prototype to avoid moving the whole function around */
1034+static const char *winbindd_socket_dir(void);
1035+
1036+struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx, const char* dir)
1037+{
1038+ struct wb_context *result;
1039+
1040+ result = talloc(mem_ctx, struct wb_context);
1041+ if (result == NULL) {
1042+ return NULL;
1043+ }
1044+ result->queue = tevent_queue_create(result, "wb_trans");
1045+ if (result->queue == NULL) {
1046+ TALLOC_FREE(result);
1047+ return NULL;
1048+ }
1049+ result->fd = -1;
1050+ result->is_priv = false;
1051+
1052+ if (dir != NULL) {
1053+ result->dir = talloc_strdup(result, dir);
1054+ } else {
1055+ result->dir = winbindd_socket_dir();
1056+ }
1057+ if (result->dir == NULL) {
1058+ TALLOC_FREE(result);
1059+ return NULL;
1060+ }
1061+ return result;
1062+}
1063+
1064+struct wb_connect_state {
1065+ int dummy;
1066+};
1067+
1068+static void wbc_connect_connected(struct tevent_req *subreq);
1069+
1070+static struct tevent_req *wb_connect_send(TALLOC_CTX *mem_ctx,
1071+ struct tevent_context *ev,
1072+ struct wb_context *wb_ctx,
1073+ const char *dir)
1074+{
1075+ struct tevent_req *result, *subreq;
1076+ struct wb_connect_state *state;
1077+ struct sockaddr_un sunaddr;
1078+ struct stat st;
1079+ char *path = NULL;
1080+ wbcErr wbc_err;
1081+
1082+ result = tevent_req_create(mem_ctx, &state, struct wb_connect_state);
1083+ if (result == NULL) {
1084+ return NULL;
1085+ }
1086+
1087+ if (wb_ctx->fd != -1) {
1088+ close(wb_ctx->fd);
1089+ wb_ctx->fd = -1;
1090+ }
1091+
1092+ /* Check permissions on unix socket directory */
1093+
1094+ if (lstat(dir, &st) == -1) {
1095+ wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
1096+ goto post_status;
1097+ }
1098+
1099+ if (!S_ISDIR(st.st_mode) ||
1100+ (st.st_uid != 0 && st.st_uid != geteuid())) {
1101+ wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
1102+ goto post_status;
1103+ }
1104+
1105+ /* Connect to socket */
1106+
1107+ path = talloc_asprintf(mem_ctx, "%s/%s", dir,
1108+ WINBINDD_SOCKET_NAME);
1109+ if (path == NULL) {
1110+ goto nomem;
1111+ }
1112+
1113+ sunaddr.sun_family = AF_UNIX;
1114+ strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
1115+ TALLOC_FREE(path);
1116+
1117+ /* If socket file doesn't exist, don't bother trying to connect
1118+ with retry. This is an attempt to make the system usable when
1119+ the winbindd daemon is not running. */
1120+
1121+ if ((lstat(sunaddr.sun_path, &st) == -1)
1122+ || !S_ISSOCK(st.st_mode)
1123+ || (st.st_uid != 0 && st.st_uid != geteuid())) {
1124+ wbc_err = WBC_ERR_WINBIND_NOT_AVAILABLE;
1125+ goto post_status;
1126+ }
1127+
1128+ wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0));
1129+ if (wb_ctx->fd == -1) {
1130+ wbc_err = map_wbc_err_from_errno(errno);
1131+ goto post_status;
1132+ }
1133+
1134+ subreq = async_connect_send(mem_ctx, ev, wb_ctx->fd,
1135+ (struct sockaddr *)(void *)&sunaddr,
1136+ sizeof(sunaddr));
1137+ if (subreq == NULL) {
1138+ goto nomem;
1139+ }
1140+ tevent_req_set_callback(subreq, wbc_connect_connected, result);
1141+ return result;
1142+
1143+ post_status:
1144+ tevent_req_error(result, wbc_err);
1145+ return tevent_req_post(result, ev);
1146+ nomem:
1147+ TALLOC_FREE(result);
1148+ return NULL;
1149+}
1150+
1151+static void wbc_connect_connected(struct tevent_req *subreq)
1152+{
1153+ struct tevent_req *req = tevent_req_callback_data(
1154+ subreq, struct tevent_req);
1155+ int res, err;
1156+
1157+ res = async_connect_recv(subreq, &err);
1158+ TALLOC_FREE(subreq);
1159+ if (res == -1) {
1160+ tevent_req_error(req, map_wbc_err_from_errno(err));
1161+ return;
1162+ }
1163+ tevent_req_done(req);
1164+}
1165+
1166+static wbcErr wb_connect_recv(struct tevent_req *req)
1167+{
1168+ return tevent_req_simple_recv_wbcerr(req);
1169+}
1170+
1171+static const char *winbindd_socket_dir(void)
1172+{
1173+#ifdef SOCKET_WRAPPER
1174+ const char *env_dir;
1175+
1176+ env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
1177+ if (env_dir) {
1178+ return env_dir;
1179+ }
1180+#endif
1181+
1182+ return WINBINDD_SOCKET_DIR;
1183+}
1184+
1185+struct wb_open_pipe_state {
1186+ struct wb_context *wb_ctx;
1187+ struct tevent_context *ev;
1188+ bool need_priv;
1189+ struct winbindd_request wb_req;
1190+};
1191+
1192+static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq);
1193+static void wb_open_pipe_ping_done(struct tevent_req *subreq);
1194+static void wb_open_pipe_getpriv_done(struct tevent_req *subreq);
1195+static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq);
1196+
1197+static struct tevent_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx,
1198+ struct tevent_context *ev,
1199+ struct wb_context *wb_ctx,
1200+ bool need_priv)
1201+{
1202+ struct tevent_req *result, *subreq;
1203+ struct wb_open_pipe_state *state;
1204+
1205+ result = tevent_req_create(mem_ctx, &state, struct wb_open_pipe_state);
1206+ if (result == NULL) {
1207+ return NULL;
1208+ }
1209+ state->wb_ctx = wb_ctx;
1210+ state->ev = ev;
1211+ state->need_priv = need_priv;
1212+
1213+ if (wb_ctx->fd != -1) {
1214+ close(wb_ctx->fd);
1215+ wb_ctx->fd = -1;
1216+ }
1217+
1218+ subreq = wb_connect_send(state, ev, wb_ctx, wb_ctx->dir);
1219+ if (subreq == NULL) {
1220+ goto fail;
1221+ }
1222+ tevent_req_set_callback(subreq, wb_open_pipe_connect_nonpriv_done,
1223+ result);
1224+ return result;
1225+
1226+ fail:
1227+ TALLOC_FREE(result);
1228+ return NULL;
1229+}
1230+
1231+static void wb_open_pipe_connect_nonpriv_done(struct tevent_req *subreq)
1232+{
1233+ struct tevent_req *req = tevent_req_callback_data(
1234+ subreq, struct tevent_req);
1235+ struct wb_open_pipe_state *state = tevent_req_data(
1236+ req, struct wb_open_pipe_state);
1237+ wbcErr wbc_err;
1238+
1239+ wbc_err = wb_connect_recv(subreq);
1240+ TALLOC_FREE(subreq);
1241+ if (!WBC_ERROR_IS_OK(wbc_err)) {
1242+ state->wb_ctx->is_priv = true;
1243+ tevent_req_error(req, wbc_err);
1244+ return;
1245+ }
1246+
1247+ ZERO_STRUCT(state->wb_req);
1248+ state->wb_req.cmd = WINBINDD_INTERFACE_VERSION;
1249+ state->wb_req.pid = getpid();
1250+
1251+ subreq = wb_simple_trans_send(state, state->ev, NULL,
1252+ state->wb_ctx->fd, &state->wb_req);
1253+ if (tevent_req_nomem(subreq, req)) {
1254+ return;
1255+ }
1256+ tevent_req_set_callback(subreq, wb_open_pipe_ping_done, req);
1257+}
1258+
1259+static void wb_open_pipe_ping_done(struct tevent_req *subreq)
1260+{
1261+ struct tevent_req *req = tevent_req_callback_data(
1262+ subreq, struct tevent_req);
1263+ struct wb_open_pipe_state *state = tevent_req_data(
1264+ req, struct wb_open_pipe_state);
1265+ struct winbindd_response *wb_resp;
1266+ int ret, err;
1267+
1268+ ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
1269+ TALLOC_FREE(subreq);
1270+ if (ret == -1) {
1271+ tevent_req_error(req, map_wbc_err_from_errno(err));
1272+ return;
1273+ }
1274+
1275+ if (!state->need_priv) {
1276+ tevent_req_done(req);
1277+ return;
1278+ }
1279+
1280+ state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR;
1281+ state->wb_req.pid = getpid();
1282+
1283+ subreq = wb_simple_trans_send(state, state->ev, NULL,
1284+ state->wb_ctx->fd, &state->wb_req);
1285+ if (tevent_req_nomem(subreq, req)) {
1286+ return;
1287+ }
1288+ tevent_req_set_callback(subreq, wb_open_pipe_getpriv_done, req);
1289+}
1290+
1291+static void wb_open_pipe_getpriv_done(struct tevent_req *subreq)
1292+{
1293+ struct tevent_req *req = tevent_req_callback_data(
1294+ subreq, struct tevent_req);
1295+ struct wb_open_pipe_state *state = tevent_req_data(
1296+ req, struct wb_open_pipe_state);
1297+ struct winbindd_response *wb_resp = NULL;
1298+ int ret, err;
1299+
1300+ ret = wb_simple_trans_recv(subreq, state, &wb_resp, &err);
1301+ TALLOC_FREE(subreq);
1302+ if (ret == -1) {
1303+ tevent_req_error(req, map_wbc_err_from_errno(err));
1304+ return;
1305+ }
1306+
1307+ close(state->wb_ctx->fd);
1308+ state->wb_ctx->fd = -1;
1309+
1310+ subreq = wb_connect_send(state, state->ev, state->wb_ctx,
1311+ (char *)wb_resp->extra_data.data);
1312+ TALLOC_FREE(wb_resp);
1313+ if (tevent_req_nomem(subreq, req)) {
1314+ return;
1315+ }
1316+ tevent_req_set_callback(subreq, wb_open_pipe_connect_priv_done, req);
1317+}
1318+
1319+static void wb_open_pipe_connect_priv_done(struct tevent_req *subreq)
1320+{
1321+ struct tevent_req *req = tevent_req_callback_data(
1322+ subreq, struct tevent_req);
1323+ struct wb_open_pipe_state *state = tevent_req_data(
1324+ req, struct wb_open_pipe_state);
1325+ wbcErr wbc_err;
1326+
1327+ wbc_err = wb_connect_recv(subreq);
1328+ TALLOC_FREE(subreq);
1329+ if (!WBC_ERROR_IS_OK(wbc_err)) {
1330+ tevent_req_error(req, wbc_err);
1331+ return;
1332+ }
1333+ state->wb_ctx->is_priv = true;
1334+ tevent_req_done(req);
1335+}
1336+
1337+static wbcErr wb_open_pipe_recv(struct tevent_req *req)
1338+{
1339+ return tevent_req_simple_recv_wbcerr(req);
1340+}
1341+
1342+struct wb_trans_state {
1343+ struct wb_trans_state *prev, *next;
1344+ struct wb_context *wb_ctx;
1345+ struct tevent_context *ev;
1346+ struct winbindd_request *wb_req;
1347+ struct winbindd_response *wb_resp;
1348+ bool need_priv;
1349+};
1350+
1351+static bool closed_fd(int fd)
1352+{
1353+ struct timeval tv;
1354+ fd_set r_fds;
1355+ int selret;
1356+
1357+ if (fd == -1) {
1358+ return true;
1359+ }
1360+
1361+ FD_ZERO(&r_fds);
1362+ FD_SET(fd, &r_fds);
1363+ ZERO_STRUCT(tv);
1364+
1365+ selret = select(fd+1, &r_fds, NULL, NULL, &tv);
1366+ if (selret == -1) {
1367+ return true;
1368+ }
1369+ if (selret == 0) {
1370+ return false;
1371+ }
1372+ return (FD_ISSET(fd, &r_fds));
1373+}
1374+
1375+static void wb_trans_trigger(struct tevent_req *req, void *private_data);
1376+static void wb_trans_connect_done(struct tevent_req *subreq);
1377+static void wb_trans_done(struct tevent_req *subreq);
1378+static void wb_trans_retry_wait_done(struct tevent_req *subreq);
1379+
1380+struct tevent_req *wb_trans_send(TALLOC_CTX *mem_ctx,
1381+ struct tevent_context *ev,
1382+ struct wb_context *wb_ctx, bool need_priv,
1383+ struct winbindd_request *wb_req)
1384+{
1385+ struct tevent_req *req;
1386+ struct wb_trans_state *state;
1387+
1388+ req = tevent_req_create(mem_ctx, &state, struct wb_trans_state);
1389+ if (req == NULL) {
1390+ return NULL;
1391+ }
1392+ state->wb_ctx = wb_ctx;
1393+ state->ev = ev;
1394+ state->wb_req = wb_req;
1395+ state->need_priv = need_priv;
1396+
1397+ if (!tevent_queue_add(wb_ctx->queue, ev, req, wb_trans_trigger,
1398+ NULL)) {
1399+ tevent_req_nomem(NULL, req);
1400+ return tevent_req_post(req, ev);
1401+ }
1402+ return req;
1403+}
1404+
1405+static void wb_trans_trigger(struct tevent_req *req, void *private_data)
1406+{
1407+ struct wb_trans_state *state = tevent_req_data(
1408+ req, struct wb_trans_state);
1409+ struct tevent_req *subreq;
1410+
1411+ if ((state->wb_ctx->fd != -1) && closed_fd(state->wb_ctx->fd)) {
1412+ close(state->wb_ctx->fd);
1413+ state->wb_ctx->fd = -1;
1414+ }
1415+
1416+ if ((state->wb_ctx->fd == -1)
1417+ || (state->need_priv && !state->wb_ctx->is_priv)) {
1418+ subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
1419+ state->need_priv);
1420+ if (tevent_req_nomem(subreq, req)) {
1421+ return;
1422+ }
1423+ tevent_req_set_callback(subreq, wb_trans_connect_done, req);
1424+ return;
1425+ }
1426+
1427+ state->wb_req->pid = getpid();
1428+
1429+ subreq = wb_simple_trans_send(state, state->ev, NULL,
1430+ state->wb_ctx->fd, state->wb_req);
1431+ if (tevent_req_nomem(subreq, req)) {
1432+ return;
1433+ }
1434+ tevent_req_set_callback(subreq, wb_trans_done, req);
1435+}
1436+
1437+static bool wb_trans_retry(struct tevent_req *req,
1438+ struct wb_trans_state *state,
1439+ wbcErr wbc_err)
1440+{
1441+ struct tevent_req *subreq;
1442+
1443+ if (WBC_ERROR_IS_OK(wbc_err)) {
1444+ return false;
1445+ }
1446+
1447+ if (wbc_err == WBC_ERR_WINBIND_NOT_AVAILABLE) {
1448+ /*
1449+ * Winbind not around or we can't connect to the pipe. Fail
1450+ * immediately.
1451+ */
1452+ tevent_req_error(req, wbc_err);
1453+ return true;
1454+ }
1455+
1456+ /*
1457+ * The transfer as such failed, retry after one second
1458+ */
1459+
1460+ if (state->wb_ctx->fd != -1) {
1461+ close(state->wb_ctx->fd);
1462+ state->wb_ctx->fd = -1;
1463+ }
1464+
1465+ subreq = tevent_wakeup_send(state, state->ev,
1466+ tevent_timeval_current_ofs(1, 0));
1467+ if (tevent_req_nomem(subreq, req)) {
1468+ return true;
1469+ }
1470+ tevent_req_set_callback(subreq, wb_trans_retry_wait_done, req);
1471+ return true;
1472+}
1473+
1474+static void wb_trans_retry_wait_done(struct tevent_req *subreq)
1475+{
1476+ struct tevent_req *req = tevent_req_callback_data(
1477+ subreq, struct tevent_req);
1478+ struct wb_trans_state *state = tevent_req_data(
1479+ req, struct wb_trans_state);
1480+ bool ret;
1481+
1482+ ret = tevent_wakeup_recv(subreq);
1483+ TALLOC_FREE(subreq);
1484+ if (!ret) {
1485+ tevent_req_error(req, WBC_ERR_UNKNOWN_FAILURE);
1486+ return;
1487+ }
1488+
1489+ subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx,
1490+ state->need_priv);
1491+ if (tevent_req_nomem(subreq, req)) {
1492+ return;
1493+ }
1494+ tevent_req_set_callback(subreq, wb_trans_connect_done, req);
1495+}
1496+
1497+static void wb_trans_connect_done(struct tevent_req *subreq)
1498+{
1499+ struct tevent_req *req = tevent_req_callback_data(
1500+ subreq, struct tevent_req);
1501+ struct wb_trans_state *state = tevent_req_data(
1502+ req, struct wb_trans_state);
1503+ wbcErr wbc_err;
1504+
1505+ wbc_err = wb_open_pipe_recv(subreq);
1506+ TALLOC_FREE(subreq);
1507+
1508+ if (wb_trans_retry(req, state, wbc_err)) {
1509+ return;
1510+ }
1511+
1512+ subreq = wb_simple_trans_send(state, state->ev, NULL,
1513+ state->wb_ctx->fd, state->wb_req);
1514+ if (tevent_req_nomem(subreq, req)) {
1515+ return;
1516+ }
1517+ tevent_req_set_callback(subreq, wb_trans_done, req);
1518+}
1519+
1520+static void wb_trans_done(struct tevent_req *subreq)
1521+{
1522+ struct tevent_req *req = tevent_req_callback_data(
1523+ subreq, struct tevent_req);
1524+ struct wb_trans_state *state = tevent_req_data(
1525+ req, struct wb_trans_state);
1526+ int ret, err;
1527+
1528+ ret = wb_simple_trans_recv(subreq, state, &state->wb_resp, &err);
1529+ TALLOC_FREE(subreq);
1530+ if ((ret == -1)
1531+ && wb_trans_retry(req, state, map_wbc_err_from_errno(err))) {
1532+ return;
1533+ }
1534+
1535+ tevent_req_done(req);
1536+}
1537+
1538+wbcErr wb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1539+ struct winbindd_response **presponse)
1540+{
1541+ struct wb_trans_state *state = tevent_req_data(
1542+ req, struct wb_trans_state);
1543+ wbcErr wbc_err;
1544+
1545+ if (tevent_req_is_wbcerr(req, &wbc_err)) {
1546+ return wbc_err;
1547+ }
1548+
1549+ *presponse = talloc_move(mem_ctx, &state->wb_resp);
1550+ return WBC_ERR_SUCCESS;
1551+}
1552+
1553+/********************************************************************
1554+ * Debug wrapper functions, modeled (with lot's of code copied as is)
1555+ * after the tevent debug wrapper functions
1556+ ********************************************************************/
1557+
1558+/*
1559+ this allows the user to choose their own debug function
1560+*/
1561+int wbcSetDebug(struct wb_context *wb_ctx,
1562+ void (*debug)(void *context,
1563+ enum wbcDebugLevel level,
1564+ const char *fmt,
1565+ va_list ap) PRINTF_ATTRIBUTE(3,0),
1566+ void *context)
1567+{
1568+ wb_ctx->debug_ops.debug = debug;
1569+ wb_ctx->debug_ops.context = context;
1570+ return 0;
1571+}
1572+
1573+/*
1574+ debug function for wbcSetDebugStderr
1575+*/
1576+static void wbcDebugStderr(void *private_data,
1577+ enum wbcDebugLevel level,
1578+ const char *fmt,
1579+ va_list ap) PRINTF_ATTRIBUTE(3,0);
1580+static void wbcDebugStderr(void *private_data,
1581+ enum wbcDebugLevel level,
1582+ const char *fmt, va_list ap)
1583+{
1584+ if (level <= WBC_DEBUG_WARNING) {
1585+ vfprintf(stderr, fmt, ap);
1586+ }
1587+}
1588+
1589+/*
1590+ convenience function to setup debug messages on stderr
1591+ messages of level WBC_DEBUG_WARNING and higher are printed
1592+*/
1593+int wbcSetDebugStderr(struct wb_context *wb_ctx)
1594+{
1595+ return wbcSetDebug(wb_ctx, wbcDebugStderr, wb_ctx);
1596+}
1597+
1598+/*
1599+ * log a message
1600+ *
1601+ * The default debug action is to ignore debugging messages.
1602+ * This is the most appropriate action for a library.
1603+ * Applications using the library must decide where to
1604+ * redirect debugging messages
1605+*/
1606+void wbcDebug(struct wb_context *wb_ctx, enum wbcDebugLevel level,
1607+ const char *fmt, ...)
1608+{
1609+ va_list ap;
1610+ if (!wb_ctx) {
1611+ return;
1612+ }
1613+ if (wb_ctx->debug_ops.debug == NULL) {
1614+ return;
1615+ }
1616+ va_start(ap, fmt);
1617+ wb_ctx->debug_ops.debug(wb_ctx->debug_ops.context, level, fmt, ap);
1618+ va_end(ap);
1619+}
1620
1621=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c'
1622--- .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 1970-01-01 00:00:00 +0000
1623+++ .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 2011-03-02 20:48:44 +0000
1624@@ -0,0 +1,690 @@
1625+/*
1626+ Unix SMB/CIFS implementation.
1627+
1628+ winbind client common code
1629+
1630+ Copyright (C) Tim Potter 2000
1631+ Copyright (C) Andrew Tridgell 2000
1632+ Copyright (C) Andrew Bartlett 2002
1633+
1634+
1635+ This library is free software; you can redistribute it and/or
1636+ modify it under the terms of the GNU Lesser General Public
1637+ License as published by the Free Software Foundation; either
1638+ version 3 of the License, or (at your option) any later version.
1639+
1640+ This library is distributed in the hope that it will be useful,
1641+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1642+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1643+ Library General Public License for more details.
1644+
1645+ You should have received a copy of the GNU Lesser General Public License
1646+ along with this program. If not, see <http://www.gnu.org/licenses/>.
1647+*/
1648+
1649+#include "winbind_client.h"
1650+
1651+/* Global variables. These are effectively the client state information */
1652+
1653+int winbindd_fd = -1; /* fd for winbindd socket */
1654+static int is_privileged = 0;
1655+
1656+/* Free a response structure */
1657+
1658+void winbindd_free_response(struct winbindd_response *response)
1659+{
1660+ /* Free any allocated extra_data */
1661+
1662+ if (response)
1663+ SAFE_FREE(response->extra_data.data);
1664+}
1665+
1666+/* Initialise a request structure */
1667+
1668+void winbindd_init_request(struct winbindd_request *request, int request_type)
1669+{
1670+ request->length = sizeof(struct winbindd_request);
1671+
1672+ request->cmd = (enum winbindd_cmd)request_type;
1673+ request->pid = getpid();
1674+
1675+}
1676+
1677+/* Initialise a response structure */
1678+
1679+static void init_response(struct winbindd_response *response)
1680+{
1681+ /* Initialise return value */
1682+
1683+ response->result = WINBINDD_ERROR;
1684+}
1685+
1686+/* Close established socket */
1687+
1688+void winbind_close_sock(void)
1689+{
1690+ if (winbindd_fd != -1) {
1691+ close(winbindd_fd);
1692+ winbindd_fd = -1;
1693+ }
1694+}
1695+
1696+#define CONNECT_TIMEOUT 30
1697+
1698+/* Make sure socket handle isn't stdin, stdout or stderr */
1699+#define RECURSION_LIMIT 3
1700+
1701+static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
1702+{
1703+ int new_fd;
1704+ if (fd >= 0 && fd <= 2) {
1705+#ifdef F_DUPFD
1706+ if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
1707+ return -1;
1708+ }
1709+ /* Paranoia */
1710+ if (new_fd < 3) {
1711+ close(new_fd);
1712+ return -1;
1713+ }
1714+ close(fd);
1715+ return new_fd;
1716+#else
1717+ if (limit <= 0)
1718+ return -1;
1719+
1720+ new_fd = dup(fd);
1721+ if (new_fd == -1)
1722+ return -1;
1723+
1724+ /* use the program stack to hold our list of FDs to close */
1725+ new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
1726+ close(fd);
1727+ return new_fd;
1728+#endif
1729+ }
1730+ return fd;
1731+}
1732+
1733+/****************************************************************************
1734+ Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
1735+ else
1736+ if SYSV use O_NDELAY
1737+ if BSD use FNDELAY
1738+ Set close on exec also.
1739+****************************************************************************/
1740+
1741+static int make_safe_fd(int fd)
1742+{
1743+ int result, flags;
1744+ int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
1745+ if (new_fd == -1) {
1746+ close(fd);
1747+ return -1;
1748+ }
1749+
1750+ /* Socket should be nonblocking. */
1751+#ifdef O_NONBLOCK
1752+#define FLAG_TO_SET O_NONBLOCK
1753+#else
1754+#ifdef SYSV
1755+#define FLAG_TO_SET O_NDELAY
1756+#else /* BSD */
1757+#define FLAG_TO_SET FNDELAY
1758+#endif
1759+#endif
1760+
1761+ if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
1762+ close(new_fd);
1763+ return -1;
1764+ }
1765+
1766+ flags |= FLAG_TO_SET;
1767+ if (fcntl(new_fd, F_SETFL, flags) == -1) {
1768+ close(new_fd);
1769+ return -1;
1770+ }
1771+
1772+#undef FLAG_TO_SET
1773+
1774+ /* Socket should be closed on exec() */
1775+#ifdef FD_CLOEXEC
1776+ result = flags = fcntl(new_fd, F_GETFD, 0);
1777+ if (flags >= 0) {
1778+ flags |= FD_CLOEXEC;
1779+ result = fcntl( new_fd, F_SETFD, flags );
1780+ }
1781+ if (result < 0) {
1782+ close(new_fd);
1783+ return -1;
1784+ }
1785+#endif
1786+ return new_fd;
1787+}
1788+
1789+/* Connect to winbindd socket */
1790+
1791+static int winbind_named_pipe_sock(const char *dir)
1792+{
1793+ struct sockaddr_un sunaddr;
1794+ struct stat st;
1795+ char *path = NULL;
1796+ int fd;
1797+ int wait_time;
1798+ int slept;
1799+
1800+ /* Check permissions on unix socket directory */
1801+
1802+ if (lstat(dir, &st) == -1) {
1803+ errno = ENOENT;
1804+ return -1;
1805+ }
1806+
1807+ if (!S_ISDIR(st.st_mode) ||
1808+ (st.st_uid != 0 && st.st_uid != geteuid())) {
1809+ errno = ENOENT;
1810+ return -1;
1811+ }
1812+
1813+ /* Connect to socket */
1814+
1815+ if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
1816+ return -1;
1817+ }
1818+
1819+ ZERO_STRUCT(sunaddr);
1820+ sunaddr.sun_family = AF_UNIX;
1821+ strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
1822+
1823+ /* If socket file doesn't exist, don't bother trying to connect
1824+ with retry. This is an attempt to make the system usable when
1825+ the winbindd daemon is not running. */
1826+
1827+ if (lstat(path, &st) == -1) {
1828+ errno = ENOENT;
1829+ SAFE_FREE(path);
1830+ return -1;
1831+ }
1832+
1833+ SAFE_FREE(path);
1834+ /* Check permissions on unix socket file */
1835+
1836+ if (!S_ISSOCK(st.st_mode) ||
1837+ (st.st_uid != 0 && st.st_uid != geteuid())) {
1838+ errno = ENOENT;
1839+ return -1;
1840+ }
1841+
1842+ /* Connect to socket */
1843+
1844+ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
1845+ return -1;
1846+ }
1847+
1848+ /* Set socket non-blocking and close on exec. */
1849+
1850+ if ((fd = make_safe_fd( fd)) == -1) {
1851+ return fd;
1852+ }
1853+
1854+ for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
1855+ wait_time += slept) {
1856+ struct timeval tv;
1857+ fd_set w_fds;
1858+ int ret;
1859+ int connect_errno = 0;
1860+ socklen_t errnosize;
1861+
1862+ if (wait_time >= CONNECT_TIMEOUT)
1863+ goto error_out;
1864+
1865+ switch (errno) {
1866+ case EINPROGRESS:
1867+ FD_ZERO(&w_fds);
1868+ FD_SET(fd, &w_fds);
1869+ tv.tv_sec = CONNECT_TIMEOUT - wait_time;
1870+ tv.tv_usec = 0;
1871+
1872+ ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
1873+
1874+ if (ret > 0) {
1875+ errnosize = sizeof(connect_errno);
1876+
1877+ ret = getsockopt(fd, SOL_SOCKET,
1878+ SO_ERROR, &connect_errno, &errnosize);
1879+
1880+ if (ret >= 0 && connect_errno == 0) {
1881+ /* Connect succeed */
1882+ goto out;
1883+ }
1884+ }
1885+
1886+ slept = CONNECT_TIMEOUT;
1887+ break;
1888+ case EAGAIN:
1889+ slept = rand() % 3 + 1;
1890+ sleep(slept);
1891+ break;
1892+ default:
1893+ goto error_out;
1894+ }
1895+
1896+ }
1897+
1898+ out:
1899+
1900+ return fd;
1901+
1902+ error_out:
1903+
1904+ close(fd);
1905+ return -1;
1906+}
1907+
1908+static const char *winbindd_socket_dir(void)
1909+{
1910+#ifdef SOCKET_WRAPPER
1911+ const char *env_dir;
1912+
1913+ env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
1914+ if (env_dir) {
1915+ return env_dir;
1916+ }
1917+#endif
1918+
1919+ return WINBINDD_SOCKET_DIR;
1920+}
1921+
1922+/* Connect to winbindd socket */
1923+
1924+static int winbind_open_pipe_sock(int recursing, int need_priv)
1925+{
1926+#ifdef HAVE_UNIXSOCKET
1927+ static pid_t our_pid;
1928+ struct winbindd_request request;
1929+ struct winbindd_response response;
1930+ ZERO_STRUCT(request);
1931+ ZERO_STRUCT(response);
1932+
1933+ if (our_pid != getpid()) {
1934+ winbind_close_sock();
1935+ our_pid = getpid();
1936+ }
1937+
1938+ if ((need_priv != 0) && (is_privileged == 0)) {
1939+ winbind_close_sock();
1940+ }
1941+
1942+ if (winbindd_fd != -1) {
1943+ return winbindd_fd;
1944+ }
1945+
1946+ if (recursing) {
1947+ return -1;
1948+ }
1949+
1950+ if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
1951+ return -1;
1952+ }
1953+
1954+ is_privileged = 0;
1955+
1956+ /* version-check the socket */
1957+
1958+ request.wb_flags = WBFLAG_RECURSE;
1959+ if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
1960+ winbind_close_sock();
1961+ return -1;
1962+ }
1963+
1964+ /* try and get priv pipe */
1965+
1966+ request.wb_flags = WBFLAG_RECURSE;
1967+ if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
1968+ int fd;
1969+ if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
1970+ close(winbindd_fd);
1971+ winbindd_fd = fd;
1972+ is_privileged = 1;
1973+ }
1974+ }
1975+
1976+ if ((need_priv != 0) && (is_privileged == 0)) {
1977+ return -1;
1978+ }
1979+
1980+ SAFE_FREE(response.extra_data.data);
1981+
1982+ return winbindd_fd;
1983+#else
1984+ return -1;
1985+#endif /* HAVE_UNIXSOCKET */
1986+}
1987+
1988+/* Write data to winbindd socket */
1989+
1990+int winbind_write_sock(void *buffer, int count, int recursing, int need_priv)
1991+{
1992+ int result, nwritten;
1993+
1994+ /* Open connection to winbind daemon */
1995+
1996+ restart:
1997+
1998+ if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
1999+ errno = ENOENT;
2000+ return -1;
2001+ }
2002+
2003+ /* Write data to socket */
2004+
2005+ nwritten = 0;
2006+
2007+ while(nwritten < count) {
2008+ struct timeval tv;
2009+ fd_set r_fds;
2010+
2011+ /* Catch pipe close on other end by checking if a read()
2012+ call would not block by calling select(). */
2013+
2014+ FD_ZERO(&r_fds);
2015+ FD_SET(winbindd_fd, &r_fds);
2016+ ZERO_STRUCT(tv);
2017+
2018+ if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
2019+ winbind_close_sock();
2020+ return -1; /* Select error */
2021+ }
2022+
2023+ /* Write should be OK if fd not available for reading */
2024+
2025+ if (!FD_ISSET(winbindd_fd, &r_fds)) {
2026+
2027+ /* Do the write */
2028+
2029+ result = write(winbindd_fd,
2030+ (char *)buffer + nwritten,
2031+ count - nwritten);
2032+
2033+ if ((result == -1) || (result == 0)) {
2034+
2035+ /* Write failed */
2036+
2037+ winbind_close_sock();
2038+ return -1;
2039+ }
2040+
2041+ nwritten += result;
2042+
2043+ } else {
2044+
2045+ /* Pipe has closed on remote end */
2046+
2047+ winbind_close_sock();
2048+ goto restart;
2049+ }
2050+ }
2051+
2052+ return nwritten;
2053+}
2054+
2055+/* Read data from winbindd socket */
2056+
2057+int winbind_read_sock(void *buffer, int count)
2058+{
2059+ int nread = 0;
2060+ int total_time = 0, selret;
2061+
2062+ if (winbindd_fd == -1) {
2063+ return -1;
2064+ }
2065+
2066+ /* Read data from socket */
2067+ while(nread < count) {
2068+ struct timeval tv;
2069+ fd_set r_fds;
2070+
2071+ /* Catch pipe close on other end by checking if a read()
2072+ call would not block by calling select(). */
2073+
2074+ FD_ZERO(&r_fds);
2075+ FD_SET(winbindd_fd, &r_fds);
2076+ ZERO_STRUCT(tv);
2077+ /* Wait for 5 seconds for a reply. May need to parameterise this... */
2078+ tv.tv_sec = 5;
2079+
2080+ if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
2081+ winbind_close_sock();
2082+ return -1; /* Select error */
2083+ }
2084+
2085+ if (selret == 0) {
2086+ /* Not ready for read yet... */
2087+ if (total_time >= 30) {
2088+ /* Timeout */
2089+ winbind_close_sock();
2090+ return -1;
2091+ }
2092+ total_time += 5;
2093+ continue;
2094+ }
2095+
2096+ if (FD_ISSET(winbindd_fd, &r_fds)) {
2097+
2098+ /* Do the Read */
2099+
2100+ int result = read(winbindd_fd, (char *)buffer + nread,
2101+ count - nread);
2102+
2103+ if ((result == -1) || (result == 0)) {
2104+
2105+ /* Read failed. I think the only useful thing we
2106+ can do here is just return -1 and fail since the
2107+ transaction has failed half way through. */
2108+
2109+ winbind_close_sock();
2110+ return -1;
2111+ }
2112+
2113+ nread += result;
2114+
2115+ }
2116+ }
2117+
2118+ return nread;
2119+}
2120+
2121+/* Read reply */
2122+
2123+int winbindd_read_reply(struct winbindd_response *response)
2124+{
2125+ int result1, result2 = 0;
2126+
2127+ if (!response) {
2128+ return -1;
2129+ }
2130+
2131+ /* Read fixed length response */
2132+
2133+ result1 = winbind_read_sock(response,
2134+ sizeof(struct winbindd_response));
2135+ if (result1 == -1) {
2136+ return -1;
2137+ }
2138+
2139+ /* We actually send the pointer value of the extra_data field from
2140+ the server. This has no meaning in the client's address space
2141+ so we clear it out. */
2142+
2143+ response->extra_data.data = NULL;
2144+
2145+ /* Read variable length response */
2146+
2147+ if (response->length > sizeof(struct winbindd_response)) {
2148+ int extra_data_len = response->length -
2149+ sizeof(struct winbindd_response);
2150+
2151+ /* Mallocate memory for extra data */
2152+
2153+ if (!(response->extra_data.data = malloc(extra_data_len))) {
2154+ return -1;
2155+ }
2156+
2157+ result2 = winbind_read_sock(response->extra_data.data,
2158+ extra_data_len);
2159+ if (result2 == -1) {
2160+ winbindd_free_response(response);
2161+ return -1;
2162+ }
2163+ }
2164+
2165+ /* Return total amount of data read */
2166+
2167+ return result1 + result2;
2168+}
2169+
2170+/*
2171+ * send simple types of requests
2172+ */
2173+
2174+NSS_STATUS winbindd_send_request(int req_type, int need_priv,
2175+ struct winbindd_request *request)
2176+{
2177+ struct winbindd_request lrequest;
2178+
2179+ /* Check for our tricky environment variable */
2180+
2181+ if (winbind_env_set()) {
2182+ return NSS_STATUS_NOTFOUND;
2183+ }
2184+
2185+ if (!request) {
2186+ ZERO_STRUCT(lrequest);
2187+ request = &lrequest;
2188+ }
2189+
2190+ /* Fill in request and send down pipe */
2191+
2192+ winbindd_init_request(request, req_type);
2193+
2194+ if (winbind_write_sock(request, sizeof(*request),
2195+ request->wb_flags & WBFLAG_RECURSE,
2196+ need_priv) == -1)
2197+ {
2198+ /* Set ENOENT for consistency. Required by some apps */
2199+ errno = ENOENT;
2200+
2201+ return NSS_STATUS_UNAVAIL;
2202+ }
2203+
2204+ if ((request->extra_len != 0) &&
2205+ (winbind_write_sock(request->extra_data.data,
2206+ request->extra_len,
2207+ request->wb_flags & WBFLAG_RECURSE,
2208+ need_priv) == -1))
2209+ {
2210+ /* Set ENOENT for consistency. Required by some apps */
2211+ errno = ENOENT;
2212+
2213+ return NSS_STATUS_UNAVAIL;
2214+ }
2215+
2216+ return NSS_STATUS_SUCCESS;
2217+}
2218+
2219+/*
2220+ * Get results from winbindd request
2221+ */
2222+
2223+NSS_STATUS winbindd_get_response(struct winbindd_response *response)
2224+{
2225+ struct winbindd_response lresponse;
2226+
2227+ if (!response) {
2228+ ZERO_STRUCT(lresponse);
2229+ response = &lresponse;
2230+ }
2231+
2232+ init_response(response);
2233+
2234+ /* Wait for reply */
2235+ if (winbindd_read_reply(response) == -1) {
2236+ /* Set ENOENT for consistency. Required by some apps */
2237+ errno = ENOENT;
2238+
2239+ return NSS_STATUS_UNAVAIL;
2240+ }
2241+
2242+ /* Throw away extra data if client didn't request it */
2243+ if (response == &lresponse) {
2244+ winbindd_free_response(response);
2245+ }
2246+
2247+ /* Copy reply data from socket */
2248+ if (response->result != WINBINDD_OK) {
2249+ return NSS_STATUS_NOTFOUND;
2250+ }
2251+
2252+ return NSS_STATUS_SUCCESS;
2253+}
2254+
2255+/* Handle simple types of requests */
2256+
2257+NSS_STATUS winbindd_request_response(int req_type,
2258+ struct winbindd_request *request,
2259+ struct winbindd_response *response)
2260+{
2261+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
2262+ int count = 0;
2263+
2264+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
2265+ status = winbindd_send_request(req_type, 0, request);
2266+ if (status != NSS_STATUS_SUCCESS)
2267+ return(status);
2268+ status = winbindd_get_response(response);
2269+ count += 1;
2270+ }
2271+
2272+ return status;
2273+}
2274+
2275+NSS_STATUS winbindd_priv_request_response(int req_type,
2276+ struct winbindd_request *request,
2277+ struct winbindd_response *response)
2278+{
2279+ NSS_STATUS status = NSS_STATUS_UNAVAIL;
2280+ int count = 0;
2281+
2282+ while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
2283+ status = winbindd_send_request(req_type, 1, request);
2284+ if (status != NSS_STATUS_SUCCESS)
2285+ return(status);
2286+ status = winbindd_get_response(response);
2287+ count += 1;
2288+ }
2289+
2290+ return status;
2291+}
2292+
2293+/*************************************************************************
2294+ ************************************************************************/
2295+
2296+const char *nss_err_str(NSS_STATUS ret)
2297+{
2298+ switch (ret) {
2299+ case NSS_STATUS_TRYAGAIN:
2300+ return "NSS_STATUS_TRYAGAIN";
2301+ case NSS_STATUS_SUCCESS:
2302+ return "NSS_STATUS_SUCCESS";
2303+ case NSS_STATUS_NOTFOUND:
2304+ return "NSS_STATUS_NOTFOUND";
2305+ case NSS_STATUS_UNAVAIL:
2306+ return "NSS_STATUS_UNAVAIL";
2307+#ifdef NSS_STATUS_RETURN
2308+ case NSS_STATUS_RETURN:
2309+ return "NSS_STATUS_RETURN";
2310+#endif
2311+ default:
2312+ return "UNKNOWN RETURN CODE!!!!!!!";
2313+ }
2314+}
2315
2316=== added directory '.pc/security-CVE-2011-0719.patch/source3'
2317=== added directory '.pc/security-CVE-2011-0719.patch/source3/client'
2318=== added file '.pc/security-CVE-2011-0719.patch/source3/client/client.c'
2319--- .pc/security-CVE-2011-0719.patch/source3/client/client.c 1970-01-01 00:00:00 +0000
2320+++ .pc/security-CVE-2011-0719.patch/source3/client/client.c 2011-03-02 20:48:44 +0000
2321@@ -0,0 +1,5041 @@
2322+/*
2323+ Unix SMB/CIFS implementation.
2324+ SMB client
2325+ Copyright (C) Andrew Tridgell 1994-1998
2326+ Copyright (C) Simo Sorce 2001-2002
2327+ Copyright (C) Jelmer Vernooij 2003
2328+ Copyright (C) Gerald (Jerry) Carter 2004
2329+ Copyright (C) Jeremy Allison 1994-2007
2330+
2331+ This program is free software; you can redistribute it and/or modify
2332+ it under the terms of the GNU General Public License as published by
2333+ the Free Software Foundation; either version 3 of the License, or
2334+ (at your option) any later version.
2335+
2336+ This program is distributed in the hope that it will be useful,
2337+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2338+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2339+ GNU General Public License for more details.
2340+
2341+ You should have received a copy of the GNU General Public License
2342+ along with this program. If not, see <http://www.gnu.org/licenses/>.
2343+*/
2344+
2345+#include "includes.h"
2346+#include "client/client_proto.h"
2347+#include "../librpc/gen_ndr/cli_srvsvc.h"
2348+
2349+#ifndef REGISTER
2350+#define REGISTER 0
2351+#endif
2352+
2353+extern int do_smb_browse(void); /* mDNS browsing */
2354+
2355+extern bool AllowDebugChange;
2356+extern bool override_logfile;
2357+extern char tar_type;
2358+
2359+static int port = 0;
2360+static char *service;
2361+static char *desthost;
2362+static char *calling_name;
2363+static bool grepable = false;
2364+static char *cmdstr = NULL;
2365+const char *cmd_ptr = NULL;
2366+
2367+static int io_bufsize = 524288;
2368+
2369+static int name_type = 0x20;
2370+static int max_protocol = PROTOCOL_NT1;
2371+
2372+static int process_tok(char *tok);
2373+static int cmd_help(void);
2374+
2375+#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
2376+
2377+/* 30 second timeout on most commands */
2378+#define CLIENT_TIMEOUT (30*1000)
2379+#define SHORT_TIMEOUT (5*1000)
2380+
2381+/* value for unused fid field in trans2 secondary request */
2382+#define FID_UNUSED (0xFFFF)
2383+
2384+time_t newer_than = 0;
2385+static int archive_level = 0;
2386+
2387+static bool translation = false;
2388+static bool have_ip;
2389+
2390+/* clitar bits insert */
2391+extern int blocksize;
2392+extern bool tar_inc;
2393+extern bool tar_reset;
2394+/* clitar bits end */
2395+
2396+static bool prompt = true;
2397+
2398+static bool recurse = false;
2399+static bool showacls = false;
2400+bool lowercase = false;
2401+
2402+static struct sockaddr_storage dest_ss;
2403+static char dest_ss_str[INET6_ADDRSTRLEN];
2404+
2405+#define SEPARATORS " \t\n\r"
2406+
2407+static bool abort_mget = true;
2408+
2409+/* timing globals */
2410+uint64_t get_total_size = 0;
2411+unsigned int get_total_time_ms = 0;
2412+static uint64_t put_total_size = 0;
2413+static unsigned int put_total_time_ms = 0;
2414+
2415+/* totals globals */
2416+static double dir_total;
2417+
2418+/* encrypted state. */
2419+static bool smb_encrypt;
2420+
2421+/* root cli_state connection */
2422+
2423+struct cli_state *cli;
2424+
2425+static char CLI_DIRSEP_CHAR = '\\';
2426+static char CLI_DIRSEP_STR[] = { '\\', '\0' };
2427+
2428+/* Authentication for client connections. */
2429+struct user_auth_info *auth_info;
2430+
2431+/* Accessor functions for directory paths. */
2432+static char *fileselection;
2433+static const char *client_get_fileselection(void)
2434+{
2435+ if (fileselection) {
2436+ return fileselection;
2437+ }
2438+ return "";
2439+}
2440+
2441+static const char *client_set_fileselection(const char *new_fs)
2442+{
2443+ SAFE_FREE(fileselection);
2444+ if (new_fs) {
2445+ fileselection = SMB_STRDUP(new_fs);
2446+ }
2447+ return client_get_fileselection();
2448+}
2449+
2450+static char *cwd;
2451+static const char *client_get_cwd(void)
2452+{
2453+ if (cwd) {
2454+ return cwd;
2455+ }
2456+ return CLI_DIRSEP_STR;
2457+}
2458+
2459+static const char *client_set_cwd(const char *new_cwd)
2460+{
2461+ SAFE_FREE(cwd);
2462+ if (new_cwd) {
2463+ cwd = SMB_STRDUP(new_cwd);
2464+ }
2465+ return client_get_cwd();
2466+}
2467+
2468+static char *cur_dir;
2469+const char *client_get_cur_dir(void)
2470+{
2471+ if (cur_dir) {
2472+ return cur_dir;
2473+ }
2474+ return CLI_DIRSEP_STR;
2475+}
2476+
2477+const char *client_set_cur_dir(const char *newdir)
2478+{
2479+ SAFE_FREE(cur_dir);
2480+ if (newdir) {
2481+ cur_dir = SMB_STRDUP(newdir);
2482+ }
2483+ return client_get_cur_dir();
2484+}
2485+
2486+/****************************************************************************
2487+ Write to a local file with CR/LF->LF translation if appropriate. Return the
2488+ number taken from the buffer. This may not equal the number written.
2489+****************************************************************************/
2490+
2491+static int writefile(int f, char *b, int n)
2492+{
2493+ int i;
2494+
2495+ if (!translation) {
2496+ return write(f,b,n);
2497+ }
2498+
2499+ i = 0;
2500+ while (i < n) {
2501+ if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
2502+ b++;i++;
2503+ }
2504+ if (write(f, b, 1) != 1) {
2505+ break;
2506+ }
2507+ b++;
2508+ i++;
2509+ }
2510+
2511+ return(i);
2512+}
2513+
2514+/****************************************************************************
2515+ Read from a file with LF->CR/LF translation if appropriate. Return the
2516+ number read. read approx n bytes.
2517+****************************************************************************/
2518+
2519+static int readfile(uint8_t *b, int n, XFILE *f)
2520+{
2521+ int i;
2522+ int c;
2523+
2524+ if (!translation)
2525+ return x_fread(b,1,n,f);
2526+
2527+ i = 0;
2528+ while (i < (n - 1) && (i < BUFFER_SIZE)) {
2529+ if ((c = x_getc(f)) == EOF) {
2530+ break;
2531+ }
2532+
2533+ if (c == '\n') { /* change all LFs to CR/LF */
2534+ b[i++] = '\r';
2535+ }
2536+
2537+ b[i++] = c;
2538+ }
2539+
2540+ return(i);
2541+}
2542+
2543+struct push_state {
2544+ XFILE *f;
2545+ SMB_OFF_T nread;
2546+};
2547+
2548+static size_t push_source(uint8_t *buf, size_t n, void *priv)
2549+{
2550+ struct push_state *state = (struct push_state *)priv;
2551+ int result;
2552+
2553+ if (x_feof(state->f)) {
2554+ return 0;
2555+ }
2556+
2557+ result = readfile(buf, n, state->f);
2558+ state->nread += result;
2559+ return result;
2560+}
2561+
2562+/****************************************************************************
2563+ Send a message.
2564+****************************************************************************/
2565+
2566+static void send_message(const char *username)
2567+{
2568+ char buf[1600];
2569+ NTSTATUS status;
2570+ int i;
2571+
2572+ d_printf("Type your message, ending it with a Control-D\n");
2573+
2574+ i = 0;
2575+ while (i<sizeof(buf)-2) {
2576+ int c = fgetc(stdin);
2577+ if (c == EOF) {
2578+ break;
2579+ }
2580+ if (c == '\n') {
2581+ buf[i++] = '\r';
2582+ }
2583+ buf[i++] = c;
2584+ }
2585+ buf[i] = '\0';
2586+
2587+ status = cli_message(cli, desthost, username, buf);
2588+ if (!NT_STATUS_IS_OK(status)) {
2589+ d_fprintf(stderr, "cli_message returned %s\n",
2590+ nt_errstr(status));
2591+ }
2592+}
2593+
2594+/****************************************************************************
2595+ Check the space on a device.
2596+****************************************************************************/
2597+
2598+static int do_dskattr(void)
2599+{
2600+ int total, bsize, avail;
2601+ struct cli_state *targetcli = NULL;
2602+ char *targetpath = NULL;
2603+ TALLOC_CTX *ctx = talloc_tos();
2604+
2605+ if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
2606+ d_printf("Error in dskattr: %s\n", cli_errstr(cli));
2607+ return 1;
2608+ }
2609+
2610+ if (!NT_STATUS_IS_OK(cli_dskattr(targetcli, &bsize, &total, &avail))) {
2611+ d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
2612+ return 1;
2613+ }
2614+
2615+ d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
2616+ total, bsize, avail);
2617+
2618+ return 0;
2619+}
2620+
2621+/****************************************************************************
2622+ Show cd/pwd.
2623+****************************************************************************/
2624+
2625+static int cmd_pwd(void)
2626+{
2627+ d_printf("Current directory is %s",service);
2628+ d_printf("%s\n",client_get_cur_dir());
2629+ return 0;
2630+}
2631+
2632+/****************************************************************************
2633+ Ensure name has correct directory separators.
2634+****************************************************************************/
2635+
2636+static void normalize_name(char *newdir)
2637+{
2638+ if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
2639+ string_replace(newdir,'/','\\');
2640+ }
2641+}
2642+
2643+/****************************************************************************
2644+ Change directory - inner section.
2645+****************************************************************************/
2646+
2647+static int do_cd(const char *new_dir)
2648+{
2649+ char *newdir = NULL;
2650+ char *saved_dir = NULL;
2651+ char *new_cd = NULL;
2652+ char *targetpath = NULL;
2653+ struct cli_state *targetcli = NULL;
2654+ SMB_STRUCT_STAT sbuf;
2655+ uint32 attributes;
2656+ int ret = 1;
2657+ TALLOC_CTX *ctx = talloc_stackframe();
2658+
2659+ newdir = talloc_strdup(ctx, new_dir);
2660+ if (!newdir) {
2661+ TALLOC_FREE(ctx);
2662+ return 1;
2663+ }
2664+
2665+ normalize_name(newdir);
2666+
2667+ /* Save the current directory in case the new directory is invalid */
2668+
2669+ saved_dir = talloc_strdup(ctx, client_get_cur_dir());
2670+ if (!saved_dir) {
2671+ TALLOC_FREE(ctx);
2672+ return 1;
2673+ }
2674+
2675+ if (*newdir == CLI_DIRSEP_CHAR) {
2676+ client_set_cur_dir(newdir);
2677+ new_cd = newdir;
2678+ } else {
2679+ new_cd = talloc_asprintf(ctx, "%s%s",
2680+ client_get_cur_dir(),
2681+ newdir);
2682+ if (!new_cd) {
2683+ goto out;
2684+ }
2685+ }
2686+
2687+ /* Ensure cur_dir ends in a DIRSEP */
2688+ if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
2689+ new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
2690+ if (!new_cd) {
2691+ goto out;
2692+ }
2693+ }
2694+ client_set_cur_dir(new_cd);
2695+
2696+ new_cd = clean_name(ctx, new_cd);
2697+ client_set_cur_dir(new_cd);
2698+
2699+ if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
2700+ d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
2701+ client_set_cur_dir(saved_dir);
2702+ goto out;
2703+ }
2704+
2705+ if (strequal(targetpath,CLI_DIRSEP_STR )) {
2706+ TALLOC_FREE(ctx);
2707+ return 0;
2708+ }
2709+
2710+ /* Use a trans2_qpathinfo to test directories for modern servers.
2711+ Except Win9x doesn't support the qpathinfo_basic() call..... */
2712+
2713+ if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
2714+ if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
2715+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
2716+ client_set_cur_dir(saved_dir);
2717+ goto out;
2718+ }
2719+
2720+ if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
2721+ d_printf("cd %s: not a directory\n", new_cd);
2722+ client_set_cur_dir(saved_dir);
2723+ goto out;
2724+ }
2725+ } else {
2726+ targetpath = talloc_asprintf(ctx,
2727+ "%s%s",
2728+ targetpath,
2729+ CLI_DIRSEP_STR );
2730+ if (!targetpath) {
2731+ client_set_cur_dir(saved_dir);
2732+ goto out;
2733+ }
2734+ targetpath = clean_name(ctx, targetpath);
2735+ if (!targetpath) {
2736+ client_set_cur_dir(saved_dir);
2737+ goto out;
2738+ }
2739+
2740+ if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, targetpath))) {
2741+ d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
2742+ client_set_cur_dir(saved_dir);
2743+ goto out;
2744+ }
2745+ }
2746+
2747+ ret = 0;
2748+
2749+out:
2750+
2751+ TALLOC_FREE(ctx);
2752+ return ret;
2753+}
2754+
2755+/****************************************************************************
2756+ Change directory.
2757+****************************************************************************/
2758+
2759+static int cmd_cd(void)
2760+{
2761+ char *buf = NULL;
2762+ int rc = 0;
2763+
2764+ if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
2765+ rc = do_cd(buf);
2766+ } else {
2767+ d_printf("Current directory is %s\n",client_get_cur_dir());
2768+ }
2769+
2770+ return rc;
2771+}
2772+
2773+/****************************************************************************
2774+ Change directory.
2775+****************************************************************************/
2776+
2777+static int cmd_cd_oneup(void)
2778+{
2779+ return do_cd("..");
2780+}
2781+
2782+/*******************************************************************
2783+ Decide if a file should be operated on.
2784+********************************************************************/
2785+
2786+static bool do_this_one(file_info *finfo)
2787+{
2788+ if (!finfo->name) {
2789+ return false;
2790+ }
2791+
2792+ if (finfo->mode & aDIR) {
2793+ return true;
2794+ }
2795+
2796+ if (*client_get_fileselection() &&
2797+ !mask_match(finfo->name,client_get_fileselection(),false)) {
2798+ DEBUG(3,("mask_match %s failed\n", finfo->name));
2799+ return false;
2800+ }
2801+
2802+ if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
2803+ DEBUG(3,("newer_than %s failed\n", finfo->name));
2804+ return false;
2805+ }
2806+
2807+ if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
2808+ DEBUG(3,("archive %s failed\n", finfo->name));
2809+ return false;
2810+ }
2811+
2812+ return true;
2813+}
2814+
2815+/****************************************************************************
2816+ Display info about a file.
2817+****************************************************************************/
2818+
2819+static void display_finfo(file_info *finfo, const char *dir)
2820+{
2821+ time_t t;
2822+ TALLOC_CTX *ctx = talloc_tos();
2823+
2824+ if (!do_this_one(finfo)) {
2825+ return;
2826+ }
2827+
2828+ t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
2829+ if (!showacls) {
2830+ d_printf(" %-30s%7.7s %8.0f %s",
2831+ finfo->name,
2832+ attrib_string(finfo->mode),
2833+ (double)finfo->size,
2834+ time_to_asc(t));
2835+ dir_total += finfo->size;
2836+ } else {
2837+ char *afname = NULL;
2838+ uint16_t fnum;
2839+
2840+ /* skip if this is . or .. */
2841+ if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
2842+ return;
2843+ /* create absolute filename for cli_ntcreate() FIXME */
2844+ afname = talloc_asprintf(ctx,
2845+ "%s%s%s",
2846+ dir,
2847+ CLI_DIRSEP_STR,
2848+ finfo->name);
2849+ if (!afname) {
2850+ return;
2851+ }
2852+ /* print file meta date header */
2853+ d_printf( "FILENAME:%s\n", finfo->name);
2854+ d_printf( "MODE:%s\n", attrib_string(finfo->mode));
2855+ d_printf( "SIZE:%.0f\n", (double)finfo->size);
2856+ d_printf( "MTIME:%s", time_to_asc(t));
2857+ if (!NT_STATUS_IS_OK(cli_ntcreate(finfo->cli, afname, 0,
2858+ CREATE_ACCESS_READ, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
2859+ FILE_OPEN, 0x0, 0x0, &fnum))) {
2860+ DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
2861+ afname,
2862+ cli_errstr( finfo->cli)));
2863+ } else {
2864+ SEC_DESC *sd = NULL;
2865+ sd = cli_query_secdesc(finfo->cli, fnum, ctx);
2866+ if (!sd) {
2867+ DEBUG( 0, ("display_finfo() failed to "
2868+ "get security descriptor: %s",
2869+ cli_errstr( finfo->cli)));
2870+ } else {
2871+ display_sec_desc(sd);
2872+ }
2873+ TALLOC_FREE(sd);
2874+ }
2875+ TALLOC_FREE(afname);
2876+ }
2877+}
2878+
2879+/****************************************************************************
2880+ Accumulate size of a file.
2881+****************************************************************************/
2882+
2883+static void do_du(file_info *finfo, const char *dir)
2884+{
2885+ if (do_this_one(finfo)) {
2886+ dir_total += finfo->size;
2887+ }
2888+}
2889+
2890+static bool do_list_recurse;
2891+static bool do_list_dirs;
2892+static char *do_list_queue = 0;
2893+static long do_list_queue_size = 0;
2894+static long do_list_queue_start = 0;
2895+static long do_list_queue_end = 0;
2896+static void (*do_list_fn)(file_info *, const char *dir);
2897+
2898+/****************************************************************************
2899+ Functions for do_list_queue.
2900+****************************************************************************/
2901+
2902+/*
2903+ * The do_list_queue is a NUL-separated list of strings stored in a
2904+ * char*. Since this is a FIFO, we keep track of the beginning and
2905+ * ending locations of the data in the queue. When we overflow, we
2906+ * double the size of the char*. When the start of the data passes
2907+ * the midpoint, we move everything back. This is logically more
2908+ * complex than a linked list, but easier from a memory management
2909+ * angle. In any memory error condition, do_list_queue is reset.
2910+ * Functions check to ensure that do_list_queue is non-NULL before
2911+ * accessing it.
2912+ */
2913+
2914+static void reset_do_list_queue(void)
2915+{
2916+ SAFE_FREE(do_list_queue);
2917+ do_list_queue_size = 0;
2918+ do_list_queue_start = 0;
2919+ do_list_queue_end = 0;
2920+}
2921+
2922+static void init_do_list_queue(void)
2923+{
2924+ reset_do_list_queue();
2925+ do_list_queue_size = 1024;
2926+ do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
2927+ if (do_list_queue == 0) {
2928+ d_printf("malloc fail for size %d\n",
2929+ (int)do_list_queue_size);
2930+ reset_do_list_queue();
2931+ } else {
2932+ memset(do_list_queue, 0, do_list_queue_size);
2933+ }
2934+}
2935+
2936+static void adjust_do_list_queue(void)
2937+{
2938+ /*
2939+ * If the starting point of the queue is more than half way through,
2940+ * move everything toward the beginning.
2941+ */
2942+
2943+ if (do_list_queue == NULL) {
2944+ DEBUG(4,("do_list_queue is empty\n"));
2945+ do_list_queue_start = do_list_queue_end = 0;
2946+ return;
2947+ }
2948+
2949+ if (do_list_queue_start == do_list_queue_end) {
2950+ DEBUG(4,("do_list_queue is empty\n"));
2951+ do_list_queue_start = do_list_queue_end = 0;
2952+ *do_list_queue = '\0';
2953+ } else if (do_list_queue_start > (do_list_queue_size / 2)) {
2954+ DEBUG(4,("sliding do_list_queue backward\n"));
2955+ memmove(do_list_queue,
2956+ do_list_queue + do_list_queue_start,
2957+ do_list_queue_end - do_list_queue_start);
2958+ do_list_queue_end -= do_list_queue_start;
2959+ do_list_queue_start = 0;
2960+ }
2961+}
2962+
2963+static void add_to_do_list_queue(const char *entry)
2964+{
2965+ long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
2966+ while (new_end > do_list_queue_size) {
2967+ do_list_queue_size *= 2;
2968+ DEBUG(4,("enlarging do_list_queue to %d\n",
2969+ (int)do_list_queue_size));
2970+ do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
2971+ if (! do_list_queue) {
2972+ d_printf("failure enlarging do_list_queue to %d bytes\n",
2973+ (int)do_list_queue_size);
2974+ reset_do_list_queue();
2975+ } else {
2976+ memset(do_list_queue + do_list_queue_size / 2,
2977+ 0, do_list_queue_size / 2);
2978+ }
2979+ }
2980+ if (do_list_queue) {
2981+ safe_strcpy_base(do_list_queue + do_list_queue_end,
2982+ entry, do_list_queue, do_list_queue_size);
2983+ do_list_queue_end = new_end;
2984+ DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
2985+ entry, (int)do_list_queue_start, (int)do_list_queue_end));
2986+ }
2987+}
2988+
2989+static char *do_list_queue_head(void)
2990+{
2991+ return do_list_queue + do_list_queue_start;
2992+}
2993+
2994+static void remove_do_list_queue_head(void)
2995+{
2996+ if (do_list_queue_end > do_list_queue_start) {
2997+ do_list_queue_start += strlen(do_list_queue_head()) + 1;
2998+ adjust_do_list_queue();
2999+ DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
3000+ (int)do_list_queue_start, (int)do_list_queue_end));
3001+ }
3002+}
3003+
3004+static int do_list_queue_empty(void)
3005+{
3006+ return (! (do_list_queue && *do_list_queue));
3007+}
3008+
3009+/****************************************************************************
3010+ A helper for do_list.
3011+****************************************************************************/
3012+
3013+static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
3014+{
3015+ TALLOC_CTX *ctx = talloc_tos();
3016+ char *dir = NULL;
3017+ char *dir_end = NULL;
3018+
3019+ /* Work out the directory. */
3020+ dir = talloc_strdup(ctx, mask);
3021+ if (!dir) {
3022+ return;
3023+ }
3024+ if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
3025+ *dir_end = '\0';
3026+ }
3027+
3028+ if (f->mode & aDIR) {
3029+ if (do_list_dirs && do_this_one(f)) {
3030+ do_list_fn(f, dir);
3031+ }
3032+ if (do_list_recurse &&
3033+ f->name &&
3034+ !strequal(f->name,".") &&
3035+ !strequal(f->name,"..")) {
3036+ char *mask2 = NULL;
3037+ char *p = NULL;
3038+
3039+ if (!f->name[0]) {
3040+ d_printf("Empty dir name returned. Possible server misconfiguration.\n");
3041+ TALLOC_FREE(dir);
3042+ return;
3043+ }
3044+
3045+ mask2 = talloc_asprintf(ctx,
3046+ "%s%s",
3047+ mntpoint,
3048+ mask);
3049+ if (!mask2) {
3050+ TALLOC_FREE(dir);
3051+ return;
3052+ }
3053+ p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
3054+ if (p) {
3055+ p[1] = 0;
3056+ } else {
3057+ mask2[0] = '\0';
3058+ }
3059+ mask2 = talloc_asprintf_append(mask2,
3060+ "%s%s*",
3061+ f->name,
3062+ CLI_DIRSEP_STR);
3063+ if (!mask2) {
3064+ TALLOC_FREE(dir);
3065+ return;
3066+ }
3067+ add_to_do_list_queue(mask2);
3068+ TALLOC_FREE(mask2);
3069+ }
3070+ TALLOC_FREE(dir);
3071+ return;
3072+ }
3073+
3074+ if (do_this_one(f)) {
3075+ do_list_fn(f,dir);
3076+ }
3077+ TALLOC_FREE(dir);
3078+}
3079+
3080+/****************************************************************************
3081+ A wrapper around cli_list that adds recursion.
3082+****************************************************************************/
3083+
3084+void do_list(const char *mask,
3085+ uint16 attribute,
3086+ void (*fn)(file_info *, const char *dir),
3087+ bool rec,
3088+ bool dirs)
3089+{
3090+ static int in_do_list = 0;
3091+ TALLOC_CTX *ctx = talloc_tos();
3092+ struct cli_state *targetcli = NULL;
3093+ char *targetpath = NULL;
3094+
3095+ if (in_do_list && rec) {
3096+ fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
3097+ exit(1);
3098+ }
3099+
3100+ in_do_list = 1;
3101+
3102+ do_list_recurse = rec;
3103+ do_list_dirs = dirs;
3104+ do_list_fn = fn;
3105+
3106+ if (rec) {
3107+ init_do_list_queue();
3108+ add_to_do_list_queue(mask);
3109+
3110+ while (!do_list_queue_empty()) {
3111+ /*
3112+ * Need to copy head so that it doesn't become
3113+ * invalid inside the call to cli_list. This
3114+ * would happen if the list were expanded
3115+ * during the call.
3116+ * Fix from E. Jay Berkenbilt (ejb@ql.org)
3117+ */
3118+ char *head = talloc_strdup(ctx, do_list_queue_head());
3119+
3120+ if (!head) {
3121+ return;
3122+ }
3123+
3124+ /* check for dfs */
3125+
3126+ if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
3127+ d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
3128+ remove_do_list_queue_head();
3129+ continue;
3130+ }
3131+
3132+ cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
3133+ remove_do_list_queue_head();
3134+ if ((! do_list_queue_empty()) && (fn == display_finfo)) {
3135+ char *next_file = do_list_queue_head();
3136+ char *save_ch = 0;
3137+ if ((strlen(next_file) >= 2) &&
3138+ (next_file[strlen(next_file) - 1] == '*') &&
3139+ (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
3140+ save_ch = next_file +
3141+ strlen(next_file) - 2;
3142+ *save_ch = '\0';
3143+ if (showacls) {
3144+ /* cwd is only used if showacls is on */
3145+ client_set_cwd(next_file);
3146+ }
3147+ }
3148+ if (!showacls) /* don't disturbe the showacls output */
3149+ d_printf("\n%s\n",next_file);
3150+ if (save_ch) {
3151+ *save_ch = CLI_DIRSEP_CHAR;
3152+ }
3153+ }
3154+ TALLOC_FREE(head);
3155+ TALLOC_FREE(targetpath);
3156+ }
3157+ } else {
3158+ /* check for dfs */
3159+ if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
3160+ if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
3161+ d_printf("%s listing %s\n",
3162+ cli_errstr(targetcli), targetpath);
3163+ }
3164+ TALLOC_FREE(targetpath);
3165+ } else {
3166+ d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
3167+ }
3168+ }
3169+
3170+ in_do_list = 0;
3171+ reset_do_list_queue();
3172+}
3173+
3174+/****************************************************************************
3175+ Get a directory listing.
3176+****************************************************************************/
3177+
3178+static int cmd_dir(void)
3179+{
3180+ TALLOC_CTX *ctx = talloc_tos();
3181+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
3182+ char *mask = NULL;
3183+ char *buf = NULL;
3184+ int rc = 1;
3185+
3186+ dir_total = 0;
3187+ mask = talloc_strdup(ctx, client_get_cur_dir());
3188+ if (!mask) {
3189+ return 1;
3190+ }
3191+
3192+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3193+ normalize_name(buf);
3194+ if (*buf == CLI_DIRSEP_CHAR) {
3195+ mask = talloc_strdup(ctx, buf);
3196+ } else {
3197+ mask = talloc_asprintf_append(mask, "%s", buf);
3198+ }
3199+ } else {
3200+ mask = talloc_asprintf_append(mask, "*");
3201+ }
3202+ if (!mask) {
3203+ return 1;
3204+ }
3205+
3206+ if (showacls) {
3207+ /* cwd is only used if showacls is on */
3208+ client_set_cwd(client_get_cur_dir());
3209+ }
3210+
3211+ do_list(mask, attribute, display_finfo, recurse, true);
3212+
3213+ rc = do_dskattr();
3214+
3215+ DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
3216+
3217+ return rc;
3218+}
3219+
3220+/****************************************************************************
3221+ Get a directory listing.
3222+****************************************************************************/
3223+
3224+static int cmd_du(void)
3225+{
3226+ TALLOC_CTX *ctx = talloc_tos();
3227+ uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
3228+ char *mask = NULL;
3229+ char *buf = NULL;
3230+ int rc = 1;
3231+
3232+ dir_total = 0;
3233+ mask = talloc_strdup(ctx, client_get_cur_dir());
3234+ if (!mask) {
3235+ return 1;
3236+ }
3237+ if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
3238+ mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
3239+ if (!mask) {
3240+ return 1;
3241+ }
3242+ }
3243+
3244+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3245+ normalize_name(buf);
3246+ if (*buf == CLI_DIRSEP_CHAR) {
3247+ mask = talloc_strdup(ctx, buf);
3248+ } else {
3249+ mask = talloc_asprintf_append(mask, "%s", buf);
3250+ }
3251+ } else {
3252+ mask = talloc_strdup(ctx, "*");
3253+ }
3254+
3255+ do_list(mask, attribute, do_du, recurse, true);
3256+
3257+ rc = do_dskattr();
3258+
3259+ d_printf("Total number of bytes: %.0f\n", dir_total);
3260+
3261+ return rc;
3262+}
3263+
3264+static int cmd_echo(void)
3265+{
3266+ TALLOC_CTX *ctx = talloc_tos();
3267+ char *num;
3268+ char *data;
3269+ NTSTATUS status;
3270+
3271+ if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
3272+ || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
3273+ d_printf("echo <num> <data>\n");
3274+ return 1;
3275+ }
3276+
3277+ status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
3278+
3279+ if (!NT_STATUS_IS_OK(status)) {
3280+ d_printf("echo failed: %s\n", nt_errstr(status));
3281+ return 1;
3282+ }
3283+
3284+ return 0;
3285+}
3286+
3287+/****************************************************************************
3288+ Get a file from rname to lname
3289+****************************************************************************/
3290+
3291+static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
3292+{
3293+ int *pfd = (int *)priv;
3294+ if (writefile(*pfd, buf, n) == -1) {
3295+ return map_nt_error_from_unix(errno);
3296+ }
3297+ return NT_STATUS_OK;
3298+}
3299+
3300+static int do_get(const char *rname, const char *lname_in, bool reget)
3301+{
3302+ TALLOC_CTX *ctx = talloc_tos();
3303+ int handle = 0;
3304+ uint16_t fnum;
3305+ bool newhandle = false;
3306+ struct timeval tp_start;
3307+ uint16 attr;
3308+ SMB_OFF_T size;
3309+ off_t start = 0;
3310+ SMB_OFF_T nread = 0;
3311+ int rc = 0;
3312+ struct cli_state *targetcli = NULL;
3313+ char *targetname = NULL;
3314+ char *lname = NULL;
3315+ NTSTATUS status;
3316+
3317+ lname = talloc_strdup(ctx, lname_in);
3318+ if (!lname) {
3319+ return 1;
3320+ }
3321+
3322+ if (lowercase) {
3323+ strlower_m(lname);
3324+ }
3325+
3326+ if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
3327+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
3328+ return 1;
3329+ }
3330+
3331+ GetTimeOfDay(&tp_start);
3332+
3333+ if (!NT_STATUS_IS_OK(cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum))) {
3334+ d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
3335+ return 1;
3336+ }
3337+
3338+ if(!strcmp(lname,"-")) {
3339+ handle = fileno(stdout);
3340+ } else {
3341+ if (reget) {
3342+ handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
3343+ if (handle >= 0) {
3344+ start = sys_lseek(handle, 0, SEEK_END);
3345+ if (start == -1) {
3346+ d_printf("Error seeking local file\n");
3347+ return 1;
3348+ }
3349+ }
3350+ } else {
3351+ handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
3352+ }
3353+ newhandle = true;
3354+ }
3355+ if (handle < 0) {
3356+ d_printf("Error opening local file %s\n",lname);
3357+ return 1;
3358+ }
3359+
3360+
3361+ if (!cli_qfileinfo(targetcli, fnum,
3362+ &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
3363+ !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum,
3364+ &attr, &size, NULL, NULL, NULL))) {
3365+ d_printf("getattrib: %s\n",cli_errstr(targetcli));
3366+ return 1;
3367+ }
3368+
3369+ DEBUG(1,("getting file %s of size %.0f as %s ",
3370+ rname, (double)size, lname));
3371+
3372+ status = cli_pull(targetcli, fnum, start, size, io_bufsize,
3373+ writefile_sink, (void *)&handle, &nread);
3374+ if (!NT_STATUS_IS_OK(status)) {
3375+ d_fprintf(stderr, "parallel_read returned %s\n",
3376+ nt_errstr(status));
3377+ cli_close(targetcli, fnum);
3378+ return 1;
3379+ }
3380+
3381+ if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
3382+ d_printf("Error %s closing remote file\n",cli_errstr(cli));
3383+ rc = 1;
3384+ }
3385+
3386+ if (newhandle) {
3387+ close(handle);
3388+ }
3389+
3390+ if (archive_level >= 2 && (attr & aARCH)) {
3391+ cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
3392+ }
3393+
3394+ {
3395+ struct timeval tp_end;
3396+ int this_time;
3397+
3398+ GetTimeOfDay(&tp_end);
3399+ this_time =
3400+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
3401+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
3402+ get_total_time_ms += this_time;
3403+ get_total_size += nread;
3404+
3405+ DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
3406+ nread / (1.024*this_time + 1.0e-4),
3407+ get_total_size / (1.024*get_total_time_ms)));
3408+ }
3409+
3410+ TALLOC_FREE(targetname);
3411+ return rc;
3412+}
3413+
3414+/****************************************************************************
3415+ Get a file.
3416+****************************************************************************/
3417+
3418+static int cmd_get(void)
3419+{
3420+ TALLOC_CTX *ctx = talloc_tos();
3421+ char *lname = NULL;
3422+ char *rname = NULL;
3423+ char *fname = NULL;
3424+
3425+ rname = talloc_strdup(ctx, client_get_cur_dir());
3426+ if (!rname) {
3427+ return 1;
3428+ }
3429+
3430+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
3431+ d_printf("get <filename> [localname]\n");
3432+ return 1;
3433+ }
3434+ rname = talloc_asprintf_append(rname, "%s", fname);
3435+ if (!rname) {
3436+ return 1;
3437+ }
3438+ rname = clean_name(ctx, rname);
3439+ if (!rname) {
3440+ return 1;
3441+ }
3442+
3443+ next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
3444+ if (!lname) {
3445+ lname = fname;
3446+ }
3447+
3448+ return do_get(rname, lname, false);
3449+}
3450+
3451+/****************************************************************************
3452+ Do an mget operation on one file.
3453+****************************************************************************/
3454+
3455+static void do_mget(file_info *finfo, const char *dir)
3456+{
3457+ TALLOC_CTX *ctx = talloc_tos();
3458+ char *rname = NULL;
3459+ char *quest = NULL;
3460+ char *saved_curdir = NULL;
3461+ char *mget_mask = NULL;
3462+ char *new_cd = NULL;
3463+
3464+ if (!finfo->name) {
3465+ return;
3466+ }
3467+
3468+ if (strequal(finfo->name,".") || strequal(finfo->name,".."))
3469+ return;
3470+
3471+ if (abort_mget) {
3472+ d_printf("mget aborted\n");
3473+ return;
3474+ }
3475+
3476+ if (finfo->mode & aDIR) {
3477+ if (asprintf(&quest,
3478+ "Get directory %s? ",finfo->name) < 0) {
3479+ return;
3480+ }
3481+ } else {
3482+ if (asprintf(&quest,
3483+ "Get file %s? ",finfo->name) < 0) {
3484+ return;
3485+ }
3486+ }
3487+
3488+ if (prompt && !yesno(quest)) {
3489+ SAFE_FREE(quest);
3490+ return;
3491+ }
3492+ SAFE_FREE(quest);
3493+
3494+ if (!(finfo->mode & aDIR)) {
3495+ rname = talloc_asprintf(ctx,
3496+ "%s%s",
3497+ client_get_cur_dir(),
3498+ finfo->name);
3499+ if (!rname) {
3500+ return;
3501+ }
3502+ do_get(rname, finfo->name, false);
3503+ TALLOC_FREE(rname);
3504+ return;
3505+ }
3506+
3507+ /* handle directories */
3508+ saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
3509+ if (!saved_curdir) {
3510+ return;
3511+ }
3512+
3513+ new_cd = talloc_asprintf(ctx,
3514+ "%s%s%s",
3515+ client_get_cur_dir(),
3516+ finfo->name,
3517+ CLI_DIRSEP_STR);
3518+ if (!new_cd) {
3519+ return;
3520+ }
3521+ client_set_cur_dir(new_cd);
3522+
3523+ string_replace(finfo->name,'\\','/');
3524+ if (lowercase) {
3525+ strlower_m(finfo->name);
3526+ }
3527+
3528+ if (!directory_exist(finfo->name) &&
3529+ mkdir(finfo->name,0777) != 0) {
3530+ d_printf("failed to create directory %s\n",finfo->name);
3531+ client_set_cur_dir(saved_curdir);
3532+ return;
3533+ }
3534+
3535+ if (chdir(finfo->name) != 0) {
3536+ d_printf("failed to chdir to directory %s\n",finfo->name);
3537+ client_set_cur_dir(saved_curdir);
3538+ return;
3539+ }
3540+
3541+ mget_mask = talloc_asprintf(ctx,
3542+ "%s*",
3543+ client_get_cur_dir());
3544+
3545+ if (!mget_mask) {
3546+ return;
3547+ }
3548+
3549+ do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
3550+ if (chdir("..") == -1) {
3551+ d_printf("do_mget: failed to chdir to .. (error %s)\n",
3552+ strerror(errno) );
3553+ }
3554+ client_set_cur_dir(saved_curdir);
3555+ TALLOC_FREE(mget_mask);
3556+ TALLOC_FREE(saved_curdir);
3557+ TALLOC_FREE(new_cd);
3558+}
3559+
3560+/****************************************************************************
3561+ View the file using the pager.
3562+****************************************************************************/
3563+
3564+static int cmd_more(void)
3565+{
3566+ TALLOC_CTX *ctx = talloc_tos();
3567+ char *rname = NULL;
3568+ char *fname = NULL;
3569+ char *lname = NULL;
3570+ char *pager_cmd = NULL;
3571+ const char *pager;
3572+ int fd;
3573+ int rc = 0;
3574+
3575+ rname = talloc_strdup(ctx, client_get_cur_dir());
3576+ if (!rname) {
3577+ return 1;
3578+ }
3579+
3580+ lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
3581+ if (!lname) {
3582+ return 1;
3583+ }
3584+ fd = mkstemp(lname);
3585+ if (fd == -1) {
3586+ d_printf("failed to create temporary file for more\n");
3587+ return 1;
3588+ }
3589+ close(fd);
3590+
3591+ if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
3592+ d_printf("more <filename>\n");
3593+ unlink(lname);
3594+ return 1;
3595+ }
3596+ rname = talloc_asprintf_append(rname, "%s", fname);
3597+ if (!rname) {
3598+ return 1;
3599+ }
3600+ rname = clean_name(ctx,rname);
3601+ if (!rname) {
3602+ return 1;
3603+ }
3604+
3605+ rc = do_get(rname, lname, false);
3606+
3607+ pager=getenv("PAGER");
3608+
3609+ pager_cmd = talloc_asprintf(ctx,
3610+ "%s %s",
3611+ (pager? pager:PAGER),
3612+ lname);
3613+ if (!pager_cmd) {
3614+ return 1;
3615+ }
3616+ if (system(pager_cmd) == -1) {
3617+ d_printf("system command '%s' returned -1\n",
3618+ pager_cmd);
3619+ }
3620+ unlink(lname);
3621+
3622+ return rc;
3623+}
3624+
3625+/****************************************************************************
3626+ Do a mget command.
3627+****************************************************************************/
3628+
3629+static int cmd_mget(void)
3630+{
3631+ TALLOC_CTX *ctx = talloc_tos();
3632+ uint16 attribute = aSYSTEM | aHIDDEN;
3633+ char *mget_mask = NULL;
3634+ char *buf = NULL;
3635+
3636+ if (recurse) {
3637+ attribute |= aDIR;
3638+ }
3639+
3640+ abort_mget = false;
3641+
3642+ while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3643+ mget_mask = talloc_strdup(ctx, client_get_cur_dir());
3644+ if (!mget_mask) {
3645+ return 1;
3646+ }
3647+ if (*buf == CLI_DIRSEP_CHAR) {
3648+ mget_mask = talloc_strdup(ctx, buf);
3649+ } else {
3650+ mget_mask = talloc_asprintf_append(mget_mask,
3651+ "%s", buf);
3652+ }
3653+ if (!mget_mask) {
3654+ return 1;
3655+ }
3656+ do_list(mget_mask, attribute, do_mget, false, true);
3657+ }
3658+
3659+ if (mget_mask == NULL) {
3660+ d_printf("nothing to mget\n");
3661+ return 0;
3662+ }
3663+
3664+ if (!*mget_mask) {
3665+ mget_mask = talloc_asprintf(ctx,
3666+ "%s*",
3667+ client_get_cur_dir());
3668+ if (!mget_mask) {
3669+ return 1;
3670+ }
3671+ do_list(mget_mask, attribute, do_mget, false, true);
3672+ }
3673+
3674+ return 0;
3675+}
3676+
3677+/****************************************************************************
3678+ Make a directory of name "name".
3679+****************************************************************************/
3680+
3681+static bool do_mkdir(const char *name)
3682+{
3683+ TALLOC_CTX *ctx = talloc_tos();
3684+ struct cli_state *targetcli;
3685+ char *targetname = NULL;
3686+
3687+ if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
3688+ d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
3689+ return false;
3690+ }
3691+
3692+ if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetname))) {
3693+ d_printf("%s making remote directory %s\n",
3694+ cli_errstr(targetcli),name);
3695+ return false;
3696+ }
3697+
3698+ return true;
3699+}
3700+
3701+/****************************************************************************
3702+ Show 8.3 name of a file.
3703+****************************************************************************/
3704+
3705+static bool do_altname(const char *name)
3706+{
3707+ fstring altname;
3708+
3709+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
3710+ d_printf("%s getting alt name for %s\n",
3711+ cli_errstr(cli),name);
3712+ return false;
3713+ }
3714+ d_printf("%s\n", altname);
3715+
3716+ return true;
3717+}
3718+
3719+/****************************************************************************
3720+ Exit client.
3721+****************************************************************************/
3722+
3723+static int cmd_quit(void)
3724+{
3725+ cli_shutdown(cli);
3726+ exit(0);
3727+ /* NOTREACHED */
3728+ return 0;
3729+}
3730+
3731+/****************************************************************************
3732+ Make a directory.
3733+****************************************************************************/
3734+
3735+static int cmd_mkdir(void)
3736+{
3737+ TALLOC_CTX *ctx = talloc_tos();
3738+ char *mask = NULL;
3739+ char *buf = NULL;
3740+
3741+ mask = talloc_strdup(ctx, client_get_cur_dir());
3742+ if (!mask) {
3743+ return 1;
3744+ }
3745+
3746+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3747+ if (!recurse) {
3748+ d_printf("mkdir <dirname>\n");
3749+ }
3750+ return 1;
3751+ }
3752+ mask = talloc_asprintf_append(mask, "%s", buf);
3753+ if (!mask) {
3754+ return 1;
3755+ }
3756+
3757+ if (recurse) {
3758+ char *ddir = NULL;
3759+ char *ddir2 = NULL;
3760+ struct cli_state *targetcli;
3761+ char *targetname = NULL;
3762+ char *p = NULL;
3763+ char *saveptr;
3764+
3765+ ddir2 = talloc_strdup(ctx, "");
3766+ if (!ddir2) {
3767+ return 1;
3768+ }
3769+
3770+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
3771+ return 1;
3772+ }
3773+
3774+ ddir = talloc_strdup(ctx, targetname);
3775+ if (!ddir) {
3776+ return 1;
3777+ }
3778+ trim_char(ddir,'.','\0');
3779+ p = strtok_r(ddir, "/\\", &saveptr);
3780+ while (p) {
3781+ ddir2 = talloc_asprintf_append(ddir2, "%s", p);
3782+ if (!ddir2) {
3783+ return 1;
3784+ }
3785+ if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
3786+ do_mkdir(ddir2);
3787+ }
3788+ ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
3789+ if (!ddir2) {
3790+ return 1;
3791+ }
3792+ p = strtok_r(NULL, "/\\", &saveptr);
3793+ }
3794+ } else {
3795+ do_mkdir(mask);
3796+ }
3797+
3798+ return 0;
3799+}
3800+
3801+/****************************************************************************
3802+ Show alt name.
3803+****************************************************************************/
3804+
3805+static int cmd_altname(void)
3806+{
3807+ TALLOC_CTX *ctx = talloc_tos();
3808+ char *name;
3809+ char *buf;
3810+
3811+ name = talloc_strdup(ctx, client_get_cur_dir());
3812+ if (!name) {
3813+ return 1;
3814+ }
3815+
3816+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3817+ d_printf("altname <file>\n");
3818+ return 1;
3819+ }
3820+ name = talloc_asprintf_append(name, "%s", buf);
3821+ if (!name) {
3822+ return 1;
3823+ }
3824+ do_altname(name);
3825+ return 0;
3826+}
3827+
3828+/****************************************************************************
3829+ Show all info we can get
3830+****************************************************************************/
3831+
3832+static int do_allinfo(const char *name)
3833+{
3834+ fstring altname;
3835+ struct timespec b_time, a_time, m_time, c_time;
3836+ SMB_OFF_T size;
3837+ uint16_t mode;
3838+ SMB_INO_T ino;
3839+ NTTIME tmp;
3840+ unsigned int num_streams;
3841+ struct stream_struct *streams;
3842+ unsigned int i;
3843+
3844+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
3845+ d_printf("%s getting alt name for %s\n",
3846+ cli_errstr(cli),name);
3847+ return false;
3848+ }
3849+ d_printf("altname: %s\n", altname);
3850+
3851+ if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
3852+ &size, &mode, &ino)) {
3853+ d_printf("%s getting pathinfo for %s\n",
3854+ cli_errstr(cli),name);
3855+ return false;
3856+ }
3857+
3858+ unix_timespec_to_nt_time(&tmp, b_time);
3859+ d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
3860+
3861+ unix_timespec_to_nt_time(&tmp, a_time);
3862+ d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
3863+
3864+ unix_timespec_to_nt_time(&tmp, m_time);
3865+ d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
3866+
3867+ unix_timespec_to_nt_time(&tmp, c_time);
3868+ d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
3869+
3870+ if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
3871+ &streams)) {
3872+ d_printf("%s getting streams for %s\n",
3873+ cli_errstr(cli),name);
3874+ return false;
3875+ }
3876+
3877+ for (i=0; i<num_streams; i++) {
3878+ d_printf("stream: [%s], %lld bytes\n", streams[i].name,
3879+ (unsigned long long)streams[i].size);
3880+ }
3881+
3882+ return 0;
3883+}
3884+
3885+/****************************************************************************
3886+ Show all info we can get
3887+****************************************************************************/
3888+
3889+static int cmd_allinfo(void)
3890+{
3891+ TALLOC_CTX *ctx = talloc_tos();
3892+ char *name;
3893+ char *buf;
3894+
3895+ name = talloc_strdup(ctx, client_get_cur_dir());
3896+ if (!name) {
3897+ return 1;
3898+ }
3899+
3900+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3901+ d_printf("allinfo <file>\n");
3902+ return 1;
3903+ }
3904+ name = talloc_asprintf_append(name, "%s", buf);
3905+ if (!name) {
3906+ return 1;
3907+ }
3908+
3909+ do_allinfo(name);
3910+
3911+ return 0;
3912+}
3913+
3914+/****************************************************************************
3915+ Put a single file.
3916+****************************************************************************/
3917+
3918+static int do_put(const char *rname, const char *lname, bool reput)
3919+{
3920+ TALLOC_CTX *ctx = talloc_tos();
3921+ uint16_t fnum;
3922+ XFILE *f;
3923+ SMB_OFF_T start = 0;
3924+ int rc = 0;
3925+ struct timeval tp_start;
3926+ struct cli_state *targetcli;
3927+ char *targetname = NULL;
3928+ struct push_state state;
3929+ NTSTATUS status;
3930+
3931+ if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
3932+ d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
3933+ return 1;
3934+ }
3935+
3936+ GetTimeOfDay(&tp_start);
3937+
3938+ if (reput) {
3939+ status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
3940+ if (NT_STATUS_IS_OK(status)) {
3941+ if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
3942+ !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL))) {
3943+ d_printf("getattrib: %s\n",cli_errstr(cli));
3944+ return 1;
3945+ }
3946+ }
3947+ } else {
3948+ status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
3949+ }
3950+
3951+ if (!NT_STATUS_IS_OK(status)) {
3952+ d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
3953+ return 1;
3954+ }
3955+
3956+ /* allow files to be piped into smbclient
3957+ jdblair 24.jun.98
3958+
3959+ Note that in this case this function will exit(0) rather
3960+ than returning. */
3961+ if (!strcmp(lname, "-")) {
3962+ f = x_stdin;
3963+ /* size of file is not known */
3964+ } else {
3965+ f = x_fopen(lname,O_RDONLY, 0);
3966+ if (f && reput) {
3967+ if (x_tseek(f, start, SEEK_SET) == -1) {
3968+ d_printf("Error seeking local file\n");
3969+ x_fclose(f);
3970+ return 1;
3971+ }
3972+ }
3973+ }
3974+
3975+ if (!f) {
3976+ d_printf("Error opening local file %s\n",lname);
3977+ return 1;
3978+ }
3979+
3980+ DEBUG(1,("putting file %s as %s ",lname,
3981+ rname));
3982+
3983+ x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
3984+
3985+ state.f = f;
3986+ state.nread = 0;
3987+
3988+ status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
3989+ &state);
3990+ if (!NT_STATUS_IS_OK(status)) {
3991+ d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
3992+ }
3993+
3994+ if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
3995+ d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
3996+ if (f != x_stdin) {
3997+ x_fclose(f);
3998+ }
3999+ return 1;
4000+ }
4001+
4002+ if (f != x_stdin) {
4003+ x_fclose(f);
4004+ }
4005+
4006+ {
4007+ struct timeval tp_end;
4008+ int this_time;
4009+
4010+ GetTimeOfDay(&tp_end);
4011+ this_time =
4012+ (tp_end.tv_sec - tp_start.tv_sec)*1000 +
4013+ (tp_end.tv_usec - tp_start.tv_usec)/1000;
4014+ put_total_time_ms += this_time;
4015+ put_total_size += state.nread;
4016+
4017+ DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
4018+ state.nread / (1.024*this_time + 1.0e-4),
4019+ put_total_size / (1.024*put_total_time_ms)));
4020+ }
4021+
4022+ if (f == x_stdin) {
4023+ cli_shutdown(cli);
4024+ exit(0);
4025+ }
4026+
4027+ return rc;
4028+}
4029+
4030+/****************************************************************************
4031+ Put a file.
4032+****************************************************************************/
4033+
4034+static int cmd_put(void)
4035+{
4036+ TALLOC_CTX *ctx = talloc_tos();
4037+ char *lname;
4038+ char *rname;
4039+ char *buf;
4040+
4041+ rname = talloc_strdup(ctx, client_get_cur_dir());
4042+ if (!rname) {
4043+ return 1;
4044+ }
4045+
4046+ if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
4047+ d_printf("put <filename>\n");
4048+ return 1;
4049+ }
4050+
4051+ if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4052+ rname = talloc_asprintf_append(rname, "%s", buf);
4053+ } else {
4054+ rname = talloc_asprintf_append(rname, "%s", lname);
4055+ }
4056+ if (!rname) {
4057+ return 1;
4058+ }
4059+
4060+ rname = clean_name(ctx, rname);
4061+ if (!rname) {
4062+ return 1;
4063+ }
4064+
4065+ {
4066+ SMB_STRUCT_STAT st;
4067+ /* allow '-' to represent stdin
4068+ jdblair, 24.jun.98 */
4069+ if (!file_exist_stat(lname, &st, false) &&
4070+ (strcmp(lname,"-"))) {
4071+ d_printf("%s does not exist\n",lname);
4072+ return 1;
4073+ }
4074+ }
4075+
4076+ return do_put(rname, lname, false);
4077+}
4078+
4079+/*************************************
4080+ File list structure.
4081+*************************************/
4082+
4083+static struct file_list {
4084+ struct file_list *prev, *next;
4085+ char *file_path;
4086+ bool isdir;
4087+} *file_list;
4088+
4089+/****************************************************************************
4090+ Free a file_list structure.
4091+****************************************************************************/
4092+
4093+static void free_file_list (struct file_list *l_head)
4094+{
4095+ struct file_list *list, *next;
4096+
4097+ for (list = l_head; list; list = next) {
4098+ next = list->next;
4099+ DLIST_REMOVE(l_head, list);
4100+ SAFE_FREE(list->file_path);
4101+ SAFE_FREE(list);
4102+ }
4103+}
4104+
4105+/****************************************************************************
4106+ Seek in a directory/file list until you get something that doesn't start with
4107+ the specified name.
4108+****************************************************************************/
4109+
4110+static bool seek_list(struct file_list *list, char *name)
4111+{
4112+ while (list) {
4113+ trim_string(list->file_path,"./","\n");
4114+ if (strncmp(list->file_path, name, strlen(name)) != 0) {
4115+ return true;
4116+ }
4117+ list = list->next;
4118+ }
4119+
4120+ return false;
4121+}
4122+
4123+/****************************************************************************
4124+ Set the file selection mask.
4125+****************************************************************************/
4126+
4127+static int cmd_select(void)
4128+{
4129+ TALLOC_CTX *ctx = talloc_tos();
4130+ char *new_fs = NULL;
4131+ next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
4132+ ;
4133+ if (new_fs) {
4134+ client_set_fileselection(new_fs);
4135+ } else {
4136+ client_set_fileselection("");
4137+ }
4138+ return 0;
4139+}
4140+
4141+/****************************************************************************
4142+ Recursive file matching function act as find
4143+ match must be always set to true when calling this function
4144+****************************************************************************/
4145+
4146+static int file_find(struct file_list **list, const char *directory,
4147+ const char *expression, bool match)
4148+{
4149+ SMB_STRUCT_DIR *dir;
4150+ struct file_list *entry;
4151+ struct stat statbuf;
4152+ int ret;
4153+ char *path;
4154+ bool isdir;
4155+ const char *dname;
4156+
4157+ dir = sys_opendir(directory);
4158+ if (!dir)
4159+ return -1;
4160+
4161+ while ((dname = readdirname(dir))) {
4162+ if (!strcmp("..", dname))
4163+ continue;
4164+ if (!strcmp(".", dname))
4165+ continue;
4166+
4167+ if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
4168+ continue;
4169+ }
4170+
4171+ isdir = false;
4172+ if (!match || !gen_fnmatch(expression, dname)) {
4173+ if (recurse) {
4174+ ret = stat(path, &statbuf);
4175+ if (ret == 0) {
4176+ if (S_ISDIR(statbuf.st_mode)) {
4177+ isdir = true;
4178+ ret = file_find(list, path, expression, false);
4179+ }
4180+ } else {
4181+ d_printf("file_find: cannot stat file %s\n", path);
4182+ }
4183+
4184+ if (ret == -1) {
4185+ SAFE_FREE(path);
4186+ sys_closedir(dir);
4187+ return -1;
4188+ }
4189+ }
4190+ entry = SMB_MALLOC_P(struct file_list);
4191+ if (!entry) {
4192+ d_printf("Out of memory in file_find\n");
4193+ sys_closedir(dir);
4194+ return -1;
4195+ }
4196+ entry->file_path = path;
4197+ entry->isdir = isdir;
4198+ DLIST_ADD(*list, entry);
4199+ } else {
4200+ SAFE_FREE(path);
4201+ }
4202+ }
4203+
4204+ sys_closedir(dir);
4205+ return 0;
4206+}
4207+
4208+/****************************************************************************
4209+ mput some files.
4210+****************************************************************************/
4211+
4212+static int cmd_mput(void)
4213+{
4214+ TALLOC_CTX *ctx = talloc_tos();
4215+ char *p = NULL;
4216+
4217+ while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
4218+ int ret;
4219+ struct file_list *temp_list;
4220+ char *quest, *lname, *rname;
4221+
4222+ file_list = NULL;
4223+
4224+ ret = file_find(&file_list, ".", p, true);
4225+ if (ret) {
4226+ free_file_list(file_list);
4227+ continue;
4228+ }
4229+
4230+ quest = NULL;
4231+ lname = NULL;
4232+ rname = NULL;
4233+
4234+ for (temp_list = file_list; temp_list;
4235+ temp_list = temp_list->next) {
4236+
4237+ SAFE_FREE(lname);
4238+ if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
4239+ continue;
4240+ }
4241+ trim_string(lname, "./", "/");
4242+
4243+ /* check if it's a directory */
4244+ if (temp_list->isdir) {
4245+ /* if (!recurse) continue; */
4246+
4247+ SAFE_FREE(quest);
4248+ if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
4249+ break;
4250+ }
4251+ if (prompt && !yesno(quest)) { /* No */
4252+ /* Skip the directory */
4253+ lname[strlen(lname)-1] = '/';
4254+ if (!seek_list(temp_list, lname))
4255+ break;
4256+ } else { /* Yes */
4257+ SAFE_FREE(rname);
4258+ if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
4259+ break;
4260+ }
4261+ normalize_name(rname);
4262+ if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
4263+ !do_mkdir(rname)) {
4264+ DEBUG (0, ("Unable to make dir, skipping..."));
4265+ /* Skip the directory */
4266+ lname[strlen(lname)-1] = '/';
4267+ if (!seek_list(temp_list, lname)) {
4268+ break;
4269+ }
4270+ }
4271+ }
4272+ continue;
4273+ } else {
4274+ SAFE_FREE(quest);
4275+ if (asprintf(&quest,"Put file %s? ", lname) < 0) {
4276+ break;
4277+ }
4278+ if (prompt && !yesno(quest)) {
4279+ /* No */
4280+ continue;
4281+ }
4282+
4283+ /* Yes */
4284+ SAFE_FREE(rname);
4285+ if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
4286+ break;
4287+ }
4288+ }
4289+
4290+ normalize_name(rname);
4291+
4292+ do_put(rname, lname, false);
4293+ }
4294+ free_file_list(file_list);
4295+ SAFE_FREE(quest);
4296+ SAFE_FREE(lname);
4297+ SAFE_FREE(rname);
4298+ }
4299+
4300+ return 0;
4301+}
4302+
4303+/****************************************************************************
4304+ Cancel a print job.
4305+****************************************************************************/
4306+
4307+static int do_cancel(int job)
4308+{
4309+ if (cli_printjob_del(cli, job)) {
4310+ d_printf("Job %d cancelled\n",job);
4311+ return 0;
4312+ } else {
4313+ d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
4314+ return 1;
4315+ }
4316+}
4317+
4318+/****************************************************************************
4319+ Cancel a print job.
4320+****************************************************************************/
4321+
4322+static int cmd_cancel(void)
4323+{
4324+ TALLOC_CTX *ctx = talloc_tos();
4325+ char *buf = NULL;
4326+ int job;
4327+
4328+ if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
4329+ d_printf("cancel <jobid> ...\n");
4330+ return 1;
4331+ }
4332+ do {
4333+ job = atoi(buf);
4334+ do_cancel(job);
4335+ } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
4336+
4337+ return 0;
4338+}
4339+
4340+/****************************************************************************
4341+ Print a file.
4342+****************************************************************************/
4343+
4344+static int cmd_print(void)
4345+{
4346+ TALLOC_CTX *ctx = talloc_tos();
4347+ char *lname = NULL;
4348+ char *rname = NULL;
4349+ char *p = NULL;
4350+
4351+ if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
4352+ d_printf("print <filename>\n");
4353+ return 1;
4354+ }
4355+
4356+ rname = talloc_strdup(ctx, lname);
4357+ if (!rname) {
4358+ return 1;
4359+ }
4360+ p = strrchr_m(rname,'/');
4361+ if (p) {
4362+ rname = talloc_asprintf(ctx,
4363+ "%s-%d",
4364+ p+1,
4365+ (int)sys_getpid());
4366+ }
4367+ if (strequal(lname,"-")) {
4368+ rname = talloc_asprintf(ctx,
4369+ "stdin-%d",
4370+ (int)sys_getpid());
4371+ }
4372+ if (!rname) {
4373+ return 1;
4374+ }
4375+
4376+ return do_put(rname, lname, false);
4377+}
4378+
4379+/****************************************************************************
4380+ Show a print queue entry.
4381+****************************************************************************/
4382+
4383+static void queue_fn(struct print_job_info *p)
4384+{
4385+ d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
4386+}
4387+
4388+/****************************************************************************
4389+ Show a print queue.
4390+****************************************************************************/
4391+
4392+static int cmd_queue(void)
4393+{
4394+ cli_print_queue(cli, queue_fn);
4395+ return 0;
4396+}
4397+
4398+/****************************************************************************
4399+ Delete some files.
4400+****************************************************************************/
4401+
4402+static void do_del(file_info *finfo, const char *dir)
4403+{
4404+ TALLOC_CTX *ctx = talloc_tos();
4405+ char *mask = NULL;
4406+
4407+ mask = talloc_asprintf(ctx,
4408+ "%s%c%s",
4409+ dir,
4410+ CLI_DIRSEP_CHAR,
4411+ finfo->name);
4412+ if (!mask) {
4413+ return;
4414+ }
4415+
4416+ if (finfo->mode & aDIR) {
4417+ TALLOC_FREE(mask);
4418+ return;
4419+ }
4420+
4421+ if (!NT_STATUS_IS_OK(cli_unlink(finfo->cli, mask, aSYSTEM | aHIDDEN))) {
4422+ d_printf("%s deleting remote file %s\n",
4423+ cli_errstr(finfo->cli),mask);
4424+ }
4425+ TALLOC_FREE(mask);
4426+}
4427+
4428+/****************************************************************************
4429+ Delete some files.
4430+****************************************************************************/
4431+
4432+static int cmd_del(void)
4433+{
4434+ TALLOC_CTX *ctx = talloc_tos();
4435+ char *mask = NULL;
4436+ char *buf = NULL;
4437+ uint16 attribute = aSYSTEM | aHIDDEN;
4438+
4439+ if (recurse) {
4440+ attribute |= aDIR;
4441+ }
4442+
4443+ mask = talloc_strdup(ctx, client_get_cur_dir());
4444+ if (!mask) {
4445+ return 1;
4446+ }
4447+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4448+ d_printf("del <filename>\n");
4449+ return 1;
4450+ }
4451+ mask = talloc_asprintf_append(mask, "%s", buf);
4452+ if (!mask) {
4453+ return 1;
4454+ }
4455+
4456+ do_list(mask,attribute,do_del,false,false);
4457+ return 0;
4458+}
4459+
4460+/****************************************************************************
4461+ Wildcard delete some files.
4462+****************************************************************************/
4463+
4464+static int cmd_wdel(void)
4465+{
4466+ TALLOC_CTX *ctx = talloc_tos();
4467+ char *mask = NULL;
4468+ char *buf = NULL;
4469+ uint16 attribute;
4470+ struct cli_state *targetcli;
4471+ char *targetname = NULL;
4472+
4473+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4474+ d_printf("wdel 0x<attrib> <wcard>\n");
4475+ return 1;
4476+ }
4477+
4478+ attribute = (uint16)strtol(buf, (char **)NULL, 16);
4479+
4480+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4481+ d_printf("wdel 0x<attrib> <wcard>\n");
4482+ return 1;
4483+ }
4484+
4485+ mask = talloc_asprintf(ctx, "%s%s",
4486+ client_get_cur_dir(),
4487+ buf);
4488+ if (!mask) {
4489+ return 1;
4490+ }
4491+
4492+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4493+ d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
4494+ return 1;
4495+ }
4496+
4497+ if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetname, attribute))) {
4498+ d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
4499+ }
4500+ return 0;
4501+}
4502+
4503+/****************************************************************************
4504+****************************************************************************/
4505+
4506+static int cmd_open(void)
4507+{
4508+ TALLOC_CTX *ctx = talloc_tos();
4509+ char *mask = NULL;
4510+ char *buf = NULL;
4511+ char *targetname = NULL;
4512+ struct cli_state *targetcli;
4513+ uint16_t fnum = (uint16_t)-1;
4514+
4515+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4516+ d_printf("open <filename>\n");
4517+ return 1;
4518+ }
4519+ mask = talloc_asprintf(ctx,
4520+ "%s%s",
4521+ client_get_cur_dir(),
4522+ buf);
4523+ if (!mask) {
4524+ return 1;
4525+ }
4526+
4527+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4528+ d_printf("open %s: %s\n", mask, cli_errstr(cli));
4529+ return 1;
4530+ }
4531+
4532+ if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
4533+ FILE_READ_DATA|FILE_WRITE_DATA, 0,
4534+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
4535+ if (NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
4536+ FILE_READ_DATA, 0,
4537+ FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
4538+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
4539+ } else {
4540+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
4541+ }
4542+ } else {
4543+ d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
4544+ }
4545+ return 0;
4546+}
4547+
4548+static int cmd_posix_encrypt(void)
4549+{
4550+ TALLOC_CTX *ctx = talloc_tos();
4551+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
4552+
4553+ if (cli->use_kerberos) {
4554+ status = cli_gss_smb_encryption_start(cli);
4555+ } else {
4556+ char *domain = NULL;
4557+ char *user = NULL;
4558+ char *password = NULL;
4559+
4560+ if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
4561+ d_printf("posix_encrypt domain user password\n");
4562+ return 1;
4563+ }
4564+
4565+ if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
4566+ d_printf("posix_encrypt domain user password\n");
4567+ return 1;
4568+ }
4569+
4570+ if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
4571+ d_printf("posix_encrypt domain user password\n");
4572+ return 1;
4573+ }
4574+
4575+ status = cli_raw_ntlm_smb_encryption_start(cli,
4576+ user,
4577+ password,
4578+ domain);
4579+ }
4580+
4581+ if (!NT_STATUS_IS_OK(status)) {
4582+ d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
4583+ } else {
4584+ d_printf("encryption on\n");
4585+ smb_encrypt = true;
4586+ }
4587+
4588+ return 0;
4589+}
4590+
4591+/****************************************************************************
4592+****************************************************************************/
4593+
4594+static int cmd_posix_open(void)
4595+{
4596+ TALLOC_CTX *ctx = talloc_tos();
4597+ char *mask = NULL;
4598+ char *buf = NULL;
4599+ char *targetname = NULL;
4600+ struct cli_state *targetcli;
4601+ mode_t mode;
4602+ uint16_t fnum;
4603+
4604+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4605+ d_printf("posix_open <filename> 0<mode>\n");
4606+ return 1;
4607+ }
4608+ mask = talloc_asprintf(ctx,
4609+ "%s%s",
4610+ client_get_cur_dir(),
4611+ buf);
4612+ if (!mask) {
4613+ return 1;
4614+ }
4615+
4616+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4617+ d_printf("posix_open <filename> 0<mode>\n");
4618+ return 1;
4619+ }
4620+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
4621+
4622+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4623+ d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
4624+ return 1;
4625+ }
4626+
4627+ if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode, &fnum))) {
4628+ if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode, &fnum))) {
4629+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
4630+ } else {
4631+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
4632+ }
4633+ } else {
4634+ d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
4635+ }
4636+
4637+ return 0;
4638+}
4639+
4640+static int cmd_posix_mkdir(void)
4641+{
4642+ TALLOC_CTX *ctx = talloc_tos();
4643+ char *mask = NULL;
4644+ char *buf = NULL;
4645+ char *targetname = NULL;
4646+ struct cli_state *targetcli;
4647+ mode_t mode;
4648+
4649+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4650+ d_printf("posix_mkdir <filename> 0<mode>\n");
4651+ return 1;
4652+ }
4653+ mask = talloc_asprintf(ctx,
4654+ "%s%s",
4655+ client_get_cur_dir(),
4656+ buf);
4657+ if (!mask) {
4658+ return 1;
4659+ }
4660+
4661+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4662+ d_printf("posix_mkdir <filename> 0<mode>\n");
4663+ return 1;
4664+ }
4665+ mode = (mode_t)strtol(buf, (char **)NULL, 8);
4666+
4667+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4668+ d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
4669+ return 1;
4670+ }
4671+
4672+ if (!NT_STATUS_IS_OK(cli_posix_mkdir(targetcli, targetname, mode))) {
4673+ d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
4674+ } else {
4675+ d_printf("posix_mkdir created directory %s\n", targetname);
4676+ }
4677+ return 0;
4678+}
4679+
4680+static int cmd_posix_unlink(void)
4681+{
4682+ TALLOC_CTX *ctx = talloc_tos();
4683+ char *mask = NULL;
4684+ char *buf = NULL;
4685+ char *targetname = NULL;
4686+ struct cli_state *targetcli;
4687+
4688+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4689+ d_printf("posix_unlink <filename>\n");
4690+ return 1;
4691+ }
4692+ mask = talloc_asprintf(ctx,
4693+ "%s%s",
4694+ client_get_cur_dir(),
4695+ buf);
4696+ if (!mask) {
4697+ return 1;
4698+ }
4699+
4700+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4701+ d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
4702+ return 1;
4703+ }
4704+
4705+ if (!NT_STATUS_IS_OK(cli_posix_unlink(targetcli, targetname))) {
4706+ d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
4707+ } else {
4708+ d_printf("posix_unlink deleted file %s\n", targetname);
4709+ }
4710+
4711+ return 0;
4712+}
4713+
4714+static int cmd_posix_rmdir(void)
4715+{
4716+ TALLOC_CTX *ctx = talloc_tos();
4717+ char *mask = NULL;
4718+ char *buf = NULL;
4719+ char *targetname = NULL;
4720+ struct cli_state *targetcli;
4721+
4722+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4723+ d_printf("posix_rmdir <filename>\n");
4724+ return 1;
4725+ }
4726+ mask = talloc_asprintf(ctx,
4727+ "%s%s",
4728+ client_get_cur_dir(),
4729+ buf);
4730+ if (!mask) {
4731+ return 1;
4732+ }
4733+
4734+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4735+ d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
4736+ return 1;
4737+ }
4738+
4739+ if (!NT_STATUS_IS_OK(cli_posix_rmdir(targetcli, targetname))) {
4740+ d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
4741+ } else {
4742+ d_printf("posix_rmdir deleted directory %s\n", targetname);
4743+ }
4744+
4745+ return 0;
4746+}
4747+
4748+static int cmd_close(void)
4749+{
4750+ TALLOC_CTX *ctx = talloc_tos();
4751+ char *buf = NULL;
4752+ int fnum;
4753+
4754+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4755+ d_printf("close <fnum>\n");
4756+ return 1;
4757+ }
4758+
4759+ fnum = atoi(buf);
4760+ /* We really should use the targetcli here.... */
4761+ if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
4762+ d_printf("close %d: %s\n", fnum, cli_errstr(cli));
4763+ return 1;
4764+ }
4765+ return 0;
4766+}
4767+
4768+static int cmd_posix(void)
4769+{
4770+ TALLOC_CTX *ctx = talloc_tos();
4771+ uint16 major, minor;
4772+ uint32 caplow, caphigh;
4773+ char *caps;
4774+ NTSTATUS status;
4775+
4776+ if (!SERVER_HAS_UNIX_CIFS(cli)) {
4777+ d_printf("Server doesn't support UNIX CIFS extensions.\n");
4778+ return 1;
4779+ }
4780+
4781+ status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
4782+ &caphigh);
4783+ if (!NT_STATUS_IS_OK(status)) {
4784+ d_printf("Can't get UNIX CIFS extensions version from "
4785+ "server: %s\n", nt_errstr(status));
4786+ return 1;
4787+ }
4788+
4789+ d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
4790+
4791+ caps = talloc_strdup(ctx, "");
4792+ if (!caps) {
4793+ return 1;
4794+ }
4795+ if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
4796+ caps = talloc_asprintf_append(caps, "locks ");
4797+ if (!caps) {
4798+ return 1;
4799+ }
4800+ }
4801+ if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
4802+ caps = talloc_asprintf_append(caps, "acls ");
4803+ if (!caps) {
4804+ return 1;
4805+ }
4806+ }
4807+ if (caplow & CIFS_UNIX_XATTTR_CAP) {
4808+ caps = talloc_asprintf_append(caps, "eas ");
4809+ if (!caps) {
4810+ return 1;
4811+ }
4812+ }
4813+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
4814+ caps = talloc_asprintf_append(caps, "pathnames ");
4815+ if (!caps) {
4816+ return 1;
4817+ }
4818+ }
4819+ if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
4820+ caps = talloc_asprintf_append(caps, "posix_path_operations ");
4821+ if (!caps) {
4822+ return 1;
4823+ }
4824+ }
4825+ if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
4826+ caps = talloc_asprintf_append(caps, "large_read ");
4827+ if (!caps) {
4828+ return 1;
4829+ }
4830+ }
4831+ if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
4832+ caps = talloc_asprintf_append(caps, "large_write ");
4833+ if (!caps) {
4834+ return 1;
4835+ }
4836+ }
4837+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
4838+ caps = talloc_asprintf_append(caps, "posix_encrypt ");
4839+ if (!caps) {
4840+ return 1;
4841+ }
4842+ }
4843+ if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
4844+ caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
4845+ if (!caps) {
4846+ return 1;
4847+ }
4848+ }
4849+
4850+ if (*caps && caps[strlen(caps)-1] == ' ') {
4851+ caps[strlen(caps)-1] = '\0';
4852+ }
4853+
4854+ d_printf("Server supports CIFS capabilities %s\n", caps);
4855+
4856+ if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
4857+ d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
4858+ return 1;
4859+ }
4860+
4861+ if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
4862+ CLI_DIRSEP_CHAR = '/';
4863+ *CLI_DIRSEP_STR = '/';
4864+ client_set_cur_dir(CLI_DIRSEP_STR);
4865+ }
4866+
4867+ return 0;
4868+}
4869+
4870+static int cmd_lock(void)
4871+{
4872+ TALLOC_CTX *ctx = talloc_tos();
4873+ char *buf = NULL;
4874+ uint64_t start, len;
4875+ enum brl_type lock_type;
4876+ int fnum;
4877+
4878+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4879+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4880+ return 1;
4881+ }
4882+ fnum = atoi(buf);
4883+
4884+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4885+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4886+ return 1;
4887+ }
4888+
4889+ if (*buf == 'r' || *buf == 'R') {
4890+ lock_type = READ_LOCK;
4891+ } else if (*buf == 'w' || *buf == 'W') {
4892+ lock_type = WRITE_LOCK;
4893+ } else {
4894+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4895+ return 1;
4896+ }
4897+
4898+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4899+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4900+ return 1;
4901+ }
4902+
4903+ start = (uint64_t)strtol(buf, (char **)NULL, 16);
4904+
4905+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4906+ d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
4907+ return 1;
4908+ }
4909+
4910+ len = (uint64_t)strtol(buf, (char **)NULL, 16);
4911+
4912+ if (!NT_STATUS_IS_OK(cli_posix_lock(cli, fnum, start, len, true, lock_type))) {
4913+ d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
4914+ }
4915+
4916+ return 0;
4917+}
4918+
4919+static int cmd_unlock(void)
4920+{
4921+ TALLOC_CTX *ctx = talloc_tos();
4922+ char *buf = NULL;
4923+ uint64_t start, len;
4924+ int fnum;
4925+
4926+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4927+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4928+ return 1;
4929+ }
4930+ fnum = atoi(buf);
4931+
4932+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4933+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4934+ return 1;
4935+ }
4936+
4937+ start = (uint64_t)strtol(buf, (char **)NULL, 16);
4938+
4939+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4940+ d_printf("unlock <fnum> <hex-start> <hex-len>\n");
4941+ return 1;
4942+ }
4943+
4944+ len = (uint64_t)strtol(buf, (char **)NULL, 16);
4945+
4946+ if (!NT_STATUS_IS_OK(cli_posix_unlock(cli, fnum, start, len))) {
4947+ d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
4948+ }
4949+
4950+ return 0;
4951+}
4952+
4953+
4954+/****************************************************************************
4955+ Remove a directory.
4956+****************************************************************************/
4957+
4958+static int cmd_rmdir(void)
4959+{
4960+ TALLOC_CTX *ctx = talloc_tos();
4961+ char *mask = NULL;
4962+ char *buf = NULL;
4963+ char *targetname = NULL;
4964+ struct cli_state *targetcli;
4965+
4966+ if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4967+ d_printf("rmdir <dirname>\n");
4968+ return 1;
4969+ }
4970+ mask = talloc_asprintf(ctx,
4971+ "%s%s",
4972+ client_get_cur_dir(),
4973+ buf);
4974+ if (!mask) {
4975+ return 1;
4976+ }
4977+
4978+ if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
4979+ d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
4980+ return 1;
4981+ }
4982+
4983+ if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetname))) {
4984+ d_printf("%s removing remote directory file %s\n",
4985+ cli_errstr(targetcli),mask);
4986+ }
4987+
4988+ return 0;
4989+}
4990+
4991+/****************************************************************************
4992+ UNIX hardlink.
4993+****************************************************************************/
4994+
4995+static int cmd_link(void)
4996+{
4997+ TALLOC_CTX *ctx = talloc_tos();
4998+ char *oldname = NULL;
4999+ char *newname = NULL;
5000+ char *buf = NULL;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches