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

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

Description of the change

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2010-01-16 07:52:30 +0000
+++ .pc/applied-patches 2011-03-02 20:47:51 +0000
@@ -17,3 +17,5 @@
17ubuntu-gecos-fix.patch17ubuntu-gecos-fix.patch
18security-CVE-2010-3069.patch18security-CVE-2010-3069.patch
19spnego-auth-win7.patch19spnego-auth-win7.patch
20security-CVE-2011-0719.patch
21ntlm-auth-lp623342.patch
2022
=== added directory '.pc/security-CVE-2011-0719.patch'
=== added directory '.pc/security-CVE-2011-0719.patch/lib'
=== added directory '.pc/security-CVE-2011-0719.patch/lib/tevent'
=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c'
--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c 1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_select.c 2011-03-02 20:47:51 +0000
@@ -0,0 +1,247 @@
1/*
2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003-2005
5 Copyright (C) Stefan Metzmacher 2005-2009
6
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "replace.h"
26#include "system/filesys.h"
27#include "system/select.h"
28#include "tevent.h"
29#include "tevent_util.h"
30#include "tevent_internal.h"
31
32struct select_event_context {
33 /* a pointer back to the generic event_context */
34 struct tevent_context *ev;
35
36 /* the maximum file descriptor number in fd_events */
37 int maxfd;
38
39 /* information for exiting from the event loop */
40 int exit_code;
41};
42
43/*
44 create a select_event_context structure.
45*/
46static int select_event_context_init(struct tevent_context *ev)
47{
48 struct select_event_context *select_ev;
49
50 select_ev = talloc_zero(ev, struct select_event_context);
51 if (!select_ev) return -1;
52 select_ev->ev = ev;
53
54 ev->additional_data = select_ev;
55 return 0;
56}
57
58/*
59 recalculate the maxfd
60*/
61static void calc_maxfd(struct select_event_context *select_ev)
62{
63 struct tevent_fd *fde;
64
65 select_ev->maxfd = 0;
66 for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
67 if (fde->fd > select_ev->maxfd) {
68 select_ev->maxfd = fde->fd;
69 }
70 }
71}
72
73
74/* to mark the ev->maxfd invalid
75 * this means we need to recalculate it
76 */
77#define EVENT_INVALID_MAXFD (-1)
78
79/*
80 destroy an fd_event
81*/
82static int select_event_fd_destructor(struct tevent_fd *fde)
83{
84 struct tevent_context *ev = fde->event_ctx;
85 struct select_event_context *select_ev = NULL;
86
87 if (ev) {
88 select_ev = talloc_get_type(ev->additional_data,
89 struct select_event_context);
90
91 if (select_ev->maxfd == fde->fd) {
92 select_ev->maxfd = EVENT_INVALID_MAXFD;
93 }
94 }
95
96 return tevent_common_fd_destructor(fde);
97}
98
99/*
100 add a fd based event
101 return NULL on failure (memory allocation error)
102*/
103static struct tevent_fd *select_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
104 int fd, uint16_t flags,
105 tevent_fd_handler_t handler,
106 void *private_data,
107 const char *handler_name,
108 const char *location)
109{
110 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
111 struct select_event_context);
112 struct tevent_fd *fde;
113
114 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
115 handler, private_data,
116 handler_name, location);
117 if (!fde) return NULL;
118
119 if (fde->fd > select_ev->maxfd) {
120 select_ev->maxfd = fde->fd;
121 }
122 talloc_set_destructor(fde, select_event_fd_destructor);
123
124 return fde;
125}
126
127/*
128 event loop handling using select()
129*/
130static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp)
131{
132 fd_set r_fds, w_fds;
133 struct tevent_fd *fde;
134 int selrtn;
135
136 /* we maybe need to recalculate the maxfd */
137 if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
138 calc_maxfd(select_ev);
139 }
140
141 FD_ZERO(&r_fds);
142 FD_ZERO(&w_fds);
143
144 /* setup any fd events */
145 for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
146 if (fde->flags & TEVENT_FD_READ) {
147 FD_SET(fde->fd, &r_fds);
148 }
149 if (fde->flags & TEVENT_FD_WRITE) {
150 FD_SET(fde->fd, &w_fds);
151 }
152 }
153
154 if (select_ev->ev->signal_events &&
155 tevent_common_check_signal(select_ev->ev)) {
156 return 0;
157 }
158
159 selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
160
161 if (selrtn == -1 && errno == EINTR &&
162 select_ev->ev->signal_events) {
163 tevent_common_check_signal(select_ev->ev);
164 return 0;
165 }
166
167 if (selrtn == -1 && errno == EBADF) {
168 /* the socket is dead! this should never
169 happen as the socket should have first been
170 made readable and that should have removed
171 the event, so this must be a bug. This is a
172 fatal error. */
173 tevent_debug(select_ev->ev, TEVENT_DEBUG_FATAL,
174 "ERROR: EBADF on select_event_loop_once\n");
175 select_ev->exit_code = EBADF;
176 return -1;
177 }
178
179 if (selrtn == 0 && tvalp) {
180 /* we don't care about a possible delay here */
181 tevent_common_loop_timer_delay(select_ev->ev);
182 return 0;
183 }
184
185 if (selrtn > 0) {
186 /* at least one file descriptor is ready - check
187 which ones and call the handler, being careful to allow
188 the handler to remove itself when called */
189 for (fde = select_ev->ev->fd_events; fde; fde = fde->next) {
190 uint16_t flags = 0;
191
192 if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
193 if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
194 if (flags) {
195 fde->handler(select_ev->ev, fde, flags, fde->private_data);
196 break;
197 }
198 }
199 }
200
201 return 0;
202}
203
204/*
205 do a single event loop using the events defined in ev
206*/
207static int select_event_loop_once(struct tevent_context *ev, const char *location)
208{
209 struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
210 struct select_event_context);
211 struct timeval tval;
212
213 if (ev->signal_events &&
214 tevent_common_check_signal(ev)) {
215 return 0;
216 }
217
218 if (ev->immediate_events &&
219 tevent_common_loop_immediate(ev)) {
220 return 0;
221 }
222
223 tval = tevent_common_loop_timer_delay(ev);
224 if (tevent_timeval_is_zero(&tval)) {
225 return 0;
226 }
227
228 return select_event_loop_select(select_ev, &tval);
229}
230
231static const struct tevent_ops select_event_ops = {
232 .context_init = select_event_context_init,
233 .add_fd = select_event_add_fd,
234 .set_fd_close_fn = tevent_common_fd_set_close_fn,
235 .get_fd_flags = tevent_common_fd_get_flags,
236 .set_fd_flags = tevent_common_fd_set_flags,
237 .add_timer = tevent_common_add_timer,
238 .schedule_immediate = tevent_common_schedule_immediate,
239 .add_signal = tevent_common_add_signal,
240 .loop_once = select_event_loop_once,
241 .loop_wait = tevent_common_loop_wait,
242};
243
244bool tevent_select_init(void)
245{
246 return tevent_register_backend("select", &select_event_ops);
247}
0248
=== added file '.pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c'
--- .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c 1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/lib/tevent/tevent_standard.c 2011-03-02 20:47:51 +0000
@@ -0,0 +1,569 @@
1/*
2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003-2005
5 Copyright (C) Stefan Metzmacher 2005-2009
6
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25/*
26 This is SAMBA's default event loop code
27
28 - we try to use epoll if configure detected support for it
29 otherwise we use select()
30 - if epoll is broken on the system or the kernel doesn't support it
31 at runtime we fallback to select()
32*/
33
34#include "replace.h"
35#include "system/filesys.h"
36#include "system/select.h"
37#include "tevent.h"
38#include "tevent_util.h"
39#include "tevent_internal.h"
40
41struct std_event_context {
42 /* a pointer back to the generic event_context */
43 struct tevent_context *ev;
44
45 /* the maximum file descriptor number in fd_events */
46 int maxfd;
47
48 /* information for exiting from the event loop */
49 int exit_code;
50
51 /* when using epoll this is the handle from epoll_create */
52 int epoll_fd;
53
54 /* our pid at the time the epoll_fd was created */
55 pid_t pid;
56};
57
58/* use epoll if it is available */
59#if HAVE_EPOLL
60/*
61 called when a epoll call fails, and we should fallback
62 to using select
63*/
64static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
65{
66 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
67 "%s (%s) - falling back to select()\n",
68 reason, strerror(errno));
69 close(std_ev->epoll_fd);
70 std_ev->epoll_fd = -1;
71 talloc_set_destructor(std_ev, NULL);
72}
73
74/*
75 map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
76*/
77static uint32_t epoll_map_flags(uint16_t flags)
78{
79 uint32_t ret = 0;
80 if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
81 if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
82 return ret;
83}
84
85/*
86 free the epoll fd
87*/
88static int epoll_ctx_destructor(struct std_event_context *std_ev)
89{
90 if (std_ev->epoll_fd != -1) {
91 close(std_ev->epoll_fd);
92 }
93 std_ev->epoll_fd = -1;
94 return 0;
95}
96
97/*
98 init the epoll fd
99*/
100static void epoll_init_ctx(struct std_event_context *std_ev)
101{
102 std_ev->epoll_fd = epoll_create(64);
103 std_ev->pid = getpid();
104 talloc_set_destructor(std_ev, epoll_ctx_destructor);
105}
106
107static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde);
108
109/*
110 reopen the epoll handle when our pid changes
111 see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an
112 demonstration of why this is needed
113 */
114static void epoll_check_reopen(struct std_event_context *std_ev)
115{
116 struct tevent_fd *fde;
117
118 if (std_ev->pid == getpid()) {
119 return;
120 }
121
122 close(std_ev->epoll_fd);
123 std_ev->epoll_fd = epoll_create(64);
124 if (std_ev->epoll_fd == -1) {
125 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
126 "Failed to recreate epoll handle after fork\n");
127 return;
128 }
129 std_ev->pid = getpid();
130 for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
131 epoll_add_event(std_ev, fde);
132 }
133}
134
135#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0)
136#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1)
137#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2)
138
139/*
140 add the epoll event to the given fd_event
141*/
142static void epoll_add_event(struct std_event_context *std_ev, struct tevent_fd *fde)
143{
144 struct epoll_event event;
145 if (std_ev->epoll_fd == -1) return;
146
147 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
148
149 /* if we don't want events yet, don't add an epoll_event */
150 if (fde->flags == 0) return;
151
152 ZERO_STRUCT(event);
153 event.events = epoll_map_flags(fde->flags);
154 event.data.ptr = fde;
155 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
156 epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed");
157 }
158 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
159
160 /* only if we want to read we want to tell the event handler about errors */
161 if (fde->flags & TEVENT_FD_READ) {
162 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
163 }
164}
165
166/*
167 delete the epoll event for given fd_event
168*/
169static void epoll_del_event(struct std_event_context *std_ev, struct tevent_fd *fde)
170{
171 struct epoll_event event;
172 if (std_ev->epoll_fd == -1) return;
173
174 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
175
176 /* if there's no epoll_event, we don't need to delete it */
177 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
178
179 ZERO_STRUCT(event);
180 event.events = epoll_map_flags(fde->flags);
181 event.data.ptr = fde;
182 epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
183 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
184}
185
186/*
187 change the epoll event to the given fd_event
188*/
189static void epoll_mod_event(struct std_event_context *std_ev, struct tevent_fd *fde)
190{
191 struct epoll_event event;
192 if (std_ev->epoll_fd == -1) return;
193
194 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
195
196 ZERO_STRUCT(event);
197 event.events = epoll_map_flags(fde->flags);
198 event.data.ptr = fde;
199 if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
200 epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed");
201 }
202
203 /* only if we want to read we want to tell the event handler about errors */
204 if (fde->flags & TEVENT_FD_READ) {
205 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
206 }
207}
208
209static void epoll_change_event(struct std_event_context *std_ev, struct tevent_fd *fde)
210{
211 bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
212 bool want_read = (fde->flags & TEVENT_FD_READ);
213 bool want_write= (fde->flags & TEVENT_FD_WRITE);
214
215 if (std_ev->epoll_fd == -1) return;
216
217 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
218
219 /* there's already an event */
220 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
221 if (want_read || (want_write && !got_error)) {
222 epoll_mod_event(std_ev, fde);
223 return;
224 }
225 /*
226 * if we want to match the select behavior, we need to remove the epoll_event
227 * when the caller isn't interested in events.
228 *
229 * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
230 */
231 epoll_del_event(std_ev, fde);
232 return;
233 }
234
235 /* there's no epoll_event attached to the fde */
236 if (want_read || (want_write && !got_error)) {
237 epoll_add_event(std_ev, fde);
238 return;
239 }
240}
241
242/*
243 event loop handling using epoll
244*/
245static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
246{
247 int ret, i;
248#define MAXEVENTS 1
249 struct epoll_event events[MAXEVENTS];
250 int timeout = -1;
251
252 if (std_ev->epoll_fd == -1) return -1;
253
254 if (tvalp) {
255 /* it's better to trigger timed events a bit later than to early */
256 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
257 }
258
259 if (std_ev->ev->signal_events &&
260 tevent_common_check_signal(std_ev->ev)) {
261 return 0;
262 }
263
264 ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout);
265
266 if (ret == -1 && errno == EINTR && std_ev->ev->signal_events) {
267 if (tevent_common_check_signal(std_ev->ev)) {
268 return 0;
269 }
270 }
271
272 if (ret == -1 && errno != EINTR) {
273 epoll_fallback_to_select(std_ev, "epoll_wait() failed");
274 return -1;
275 }
276
277 if (ret == 0 && tvalp) {
278 /* we don't care about a possible delay here */
279 tevent_common_loop_timer_delay(std_ev->ev);
280 return 0;
281 }
282
283 for (i=0;i<ret;i++) {
284 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr,
285 struct tevent_fd);
286 uint16_t flags = 0;
287
288 if (fde == NULL) {
289 epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data");
290 return -1;
291 }
292 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
293 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
294 /*
295 * if we only wait for TEVENT_FD_WRITE, we should not tell the
296 * event handler about it, and remove the epoll_event,
297 * as we only report errors when waiting for read events,
298 * to match the select() behavior
299 */
300 if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
301 epoll_del_event(std_ev, fde);
302 continue;
303 }
304 flags |= TEVENT_FD_READ;
305 }
306 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
307 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
308 if (flags) {
309 fde->handler(std_ev->ev, fde, flags, fde->private_data);
310 break;
311 }
312 }
313
314 return 0;
315}
316#else
317#define epoll_init_ctx(std_ev)
318#define epoll_add_event(std_ev,fde)
319#define epoll_del_event(std_ev,fde)
320#define epoll_change_event(std_ev,fde)
321#define epoll_event_loop(std_ev,tvalp) (-1)
322#define epoll_check_reopen(std_ev)
323#endif
324
325/*
326 create a std_event_context structure.
327*/
328static int std_event_context_init(struct tevent_context *ev)
329{
330 struct std_event_context *std_ev;
331
332 std_ev = talloc_zero(ev, struct std_event_context);
333 if (!std_ev) return -1;
334 std_ev->ev = ev;
335 std_ev->epoll_fd = -1;
336
337 epoll_init_ctx(std_ev);
338
339 ev->additional_data = std_ev;
340 return 0;
341}
342
343/*
344 recalculate the maxfd
345*/
346static void calc_maxfd(struct std_event_context *std_ev)
347{
348 struct tevent_fd *fde;
349
350 std_ev->maxfd = 0;
351 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
352 if (fde->fd > std_ev->maxfd) {
353 std_ev->maxfd = fde->fd;
354 }
355 }
356}
357
358
359/* to mark the ev->maxfd invalid
360 * this means we need to recalculate it
361 */
362#define EVENT_INVALID_MAXFD (-1)
363
364/*
365 destroy an fd_event
366*/
367static int std_event_fd_destructor(struct tevent_fd *fde)
368{
369 struct tevent_context *ev = fde->event_ctx;
370 struct std_event_context *std_ev = NULL;
371
372 if (ev) {
373 std_ev = talloc_get_type(ev->additional_data,
374 struct std_event_context);
375
376 epoll_check_reopen(std_ev);
377
378 if (std_ev->maxfd == fde->fd) {
379 std_ev->maxfd = EVENT_INVALID_MAXFD;
380 }
381
382 epoll_del_event(std_ev, fde);
383 }
384
385 return tevent_common_fd_destructor(fde);
386}
387
388/*
389 add a fd based event
390 return NULL on failure (memory allocation error)
391*/
392static struct tevent_fd *std_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
393 int fd, uint16_t flags,
394 tevent_fd_handler_t handler,
395 void *private_data,
396 const char *handler_name,
397 const char *location)
398{
399 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
400 struct std_event_context);
401 struct tevent_fd *fde;
402
403 epoll_check_reopen(std_ev);
404
405 fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
406 handler, private_data,
407 handler_name, location);
408 if (!fde) return NULL;
409
410 if ((std_ev->maxfd != EVENT_INVALID_MAXFD)
411 && (fde->fd > std_ev->maxfd)) {
412 std_ev->maxfd = fde->fd;
413 }
414 talloc_set_destructor(fde, std_event_fd_destructor);
415
416 epoll_add_event(std_ev, fde);
417
418 return fde;
419}
420
421/*
422 set the fd event flags
423*/
424static void std_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
425{
426 struct tevent_context *ev;
427 struct std_event_context *std_ev;
428
429 if (fde->flags == flags) return;
430
431 ev = fde->event_ctx;
432 std_ev = talloc_get_type(ev->additional_data, struct std_event_context);
433
434 fde->flags = flags;
435
436 epoll_check_reopen(std_ev);
437
438 epoll_change_event(std_ev, fde);
439}
440
441/*
442 event loop handling using select()
443*/
444static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
445{
446 fd_set r_fds, w_fds;
447 struct tevent_fd *fde;
448 int selrtn;
449
450 /* we maybe need to recalculate the maxfd */
451 if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
452 calc_maxfd(std_ev);
453 }
454
455 FD_ZERO(&r_fds);
456 FD_ZERO(&w_fds);
457
458 /* setup any fd events */
459 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
460 if (fde->flags & TEVENT_FD_READ) {
461 FD_SET(fde->fd, &r_fds);
462 }
463 if (fde->flags & TEVENT_FD_WRITE) {
464 FD_SET(fde->fd, &w_fds);
465 }
466 }
467
468 if (std_ev->ev->signal_events &&
469 tevent_common_check_signal(std_ev->ev)) {
470 return 0;
471 }
472
473 selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
474
475 if (selrtn == -1 && errno == EINTR &&
476 std_ev->ev->signal_events) {
477 tevent_common_check_signal(std_ev->ev);
478 return 0;
479 }
480
481 if (selrtn == -1 && errno == EBADF) {
482 /* the socket is dead! this should never
483 happen as the socket should have first been
484 made readable and that should have removed
485 the event, so this must be a bug. This is a
486 fatal error. */
487 tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
488 "ERROR: EBADF on std_event_loop_once\n");
489 std_ev->exit_code = EBADF;
490 return -1;
491 }
492
493 if (selrtn == 0 && tvalp) {
494 /* we don't care about a possible delay here */
495 tevent_common_loop_timer_delay(std_ev->ev);
496 return 0;
497 }
498
499 if (selrtn > 0) {
500 /* at least one file descriptor is ready - check
501 which ones and call the handler, being careful to allow
502 the handler to remove itself when called */
503 for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
504 uint16_t flags = 0;
505
506 if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
507 if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
508 if (flags) {
509 fde->handler(std_ev->ev, fde, flags, fde->private_data);
510 break;
511 }
512 }
513 }
514
515 return 0;
516}
517
518/*
519 do a single event loop using the events defined in ev
520*/
521static int std_event_loop_once(struct tevent_context *ev, const char *location)
522{
523 struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
524 struct std_event_context);
525 struct timeval tval;
526
527 if (ev->signal_events &&
528 tevent_common_check_signal(ev)) {
529 return 0;
530 }
531
532 if (ev->immediate_events &&
533 tevent_common_loop_immediate(ev)) {
534 return 0;
535 }
536
537 tval = tevent_common_loop_timer_delay(ev);
538 if (tevent_timeval_is_zero(&tval)) {
539 return 0;
540 }
541
542 epoll_check_reopen(std_ev);
543
544 if (epoll_event_loop(std_ev, &tval) == 0) {
545 return 0;
546 }
547
548 return std_event_loop_select(std_ev, &tval);
549}
550
551static const struct tevent_ops std_event_ops = {
552 .context_init = std_event_context_init,
553 .add_fd = std_event_add_fd,
554 .set_fd_close_fn = tevent_common_fd_set_close_fn,
555 .get_fd_flags = tevent_common_fd_get_flags,
556 .set_fd_flags = std_event_set_fd_flags,
557 .add_timer = tevent_common_add_timer,
558 .schedule_immediate = tevent_common_schedule_immediate,
559 .add_signal = tevent_common_add_signal,
560 .loop_once = std_event_loop_once,
561 .loop_wait = tevent_common_loop_wait,
562};
563
564
565bool tevent_standard_init(void)
566{
567 return tevent_register_backend("standard", &std_event_ops);
568}
569
0570
=== added directory '.pc/security-CVE-2011-0719.patch/nsswitch'
=== added file '.pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c'
--- .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/nsswitch/wb_common.c 2011-03-02 20:47:51 +0000
@@ -0,0 +1,690 @@
1/*
2 Unix SMB/CIFS implementation.
3
4 winbind client common code
5
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Tridgell 2000
8 Copyright (C) Andrew Bartlett 2002
9
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
15
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Library General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "winbind_client.h"
26
27/* Global variables. These are effectively the client state information */
28
29int winbindd_fd = -1; /* fd for winbindd socket */
30static int is_privileged = 0;
31
32/* Free a response structure */
33
34void winbindd_free_response(struct winbindd_response *response)
35{
36 /* Free any allocated extra_data */
37
38 if (response)
39 SAFE_FREE(response->extra_data.data);
40}
41
42/* Initialise a request structure */
43
44void winbindd_init_request(struct winbindd_request *request, int request_type)
45{
46 request->length = sizeof(struct winbindd_request);
47
48 request->cmd = (enum winbindd_cmd)request_type;
49 request->pid = getpid();
50
51}
52
53/* Initialise a response structure */
54
55static void init_response(struct winbindd_response *response)
56{
57 /* Initialise return value */
58
59 response->result = WINBINDD_ERROR;
60}
61
62/* Close established socket */
63
64void winbind_close_sock(void)
65{
66 if (winbindd_fd != -1) {
67 close(winbindd_fd);
68 winbindd_fd = -1;
69 }
70}
71
72#define CONNECT_TIMEOUT 30
73
74/* Make sure socket handle isn't stdin, stdout or stderr */
75#define RECURSION_LIMIT 3
76
77static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
78{
79 int new_fd;
80 if (fd >= 0 && fd <= 2) {
81#ifdef F_DUPFD
82 if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
83 return -1;
84 }
85 /* Paranoia */
86 if (new_fd < 3) {
87 close(new_fd);
88 return -1;
89 }
90 close(fd);
91 return new_fd;
92#else
93 if (limit <= 0)
94 return -1;
95
96 new_fd = dup(fd);
97 if (new_fd == -1)
98 return -1;
99
100 /* use the program stack to hold our list of FDs to close */
101 new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
102 close(fd);
103 return new_fd;
104#endif
105 }
106 return fd;
107}
108
109/****************************************************************************
110 Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
111 else
112 if SYSV use O_NDELAY
113 if BSD use FNDELAY
114 Set close on exec also.
115****************************************************************************/
116
117static int make_safe_fd(int fd)
118{
119 int result, flags;
120 int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
121 if (new_fd == -1) {
122 close(fd);
123 return -1;
124 }
125
126 /* Socket should be nonblocking. */
127#ifdef O_NONBLOCK
128#define FLAG_TO_SET O_NONBLOCK
129#else
130#ifdef SYSV
131#define FLAG_TO_SET O_NDELAY
132#else /* BSD */
133#define FLAG_TO_SET FNDELAY
134#endif
135#endif
136
137 if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
138 close(new_fd);
139 return -1;
140 }
141
142 flags |= FLAG_TO_SET;
143 if (fcntl(new_fd, F_SETFL, flags) == -1) {
144 close(new_fd);
145 return -1;
146 }
147
148#undef FLAG_TO_SET
149
150 /* Socket should be closed on exec() */
151#ifdef FD_CLOEXEC
152 result = flags = fcntl(new_fd, F_GETFD, 0);
153 if (flags >= 0) {
154 flags |= FD_CLOEXEC;
155 result = fcntl( new_fd, F_SETFD, flags );
156 }
157 if (result < 0) {
158 close(new_fd);
159 return -1;
160 }
161#endif
162 return new_fd;
163}
164
165/* Connect to winbindd socket */
166
167static int winbind_named_pipe_sock(const char *dir)
168{
169 struct sockaddr_un sunaddr;
170 struct stat st;
171 char *path = NULL;
172 int fd;
173 int wait_time;
174 int slept;
175
176 /* Check permissions on unix socket directory */
177
178 if (lstat(dir, &st) == -1) {
179 errno = ENOENT;
180 return -1;
181 }
182
183 if (!S_ISDIR(st.st_mode) ||
184 (st.st_uid != 0 && st.st_uid != geteuid())) {
185 errno = ENOENT;
186 return -1;
187 }
188
189 /* Connect to socket */
190
191 if (asprintf(&path, "%s/%s", dir, WINBINDD_SOCKET_NAME) < 0) {
192 return -1;
193 }
194
195 ZERO_STRUCT(sunaddr);
196 sunaddr.sun_family = AF_UNIX;
197 strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
198
199 /* If socket file doesn't exist, don't bother trying to connect
200 with retry. This is an attempt to make the system usable when
201 the winbindd daemon is not running. */
202
203 if (lstat(path, &st) == -1) {
204 errno = ENOENT;
205 SAFE_FREE(path);
206 return -1;
207 }
208
209 SAFE_FREE(path);
210 /* Check permissions on unix socket file */
211
212 if (!S_ISSOCK(st.st_mode) ||
213 (st.st_uid != 0 && st.st_uid != geteuid())) {
214 errno = ENOENT;
215 return -1;
216 }
217
218 /* Connect to socket */
219
220 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
221 return -1;
222 }
223
224 /* Set socket non-blocking and close on exec. */
225
226 if ((fd = make_safe_fd( fd)) == -1) {
227 return fd;
228 }
229
230 for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
231 wait_time += slept) {
232 struct timeval tv;
233 fd_set w_fds;
234 int ret;
235 int connect_errno = 0;
236 socklen_t errnosize;
237
238 if (wait_time >= CONNECT_TIMEOUT)
239 goto error_out;
240
241 switch (errno) {
242 case EINPROGRESS:
243 FD_ZERO(&w_fds);
244 FD_SET(fd, &w_fds);
245 tv.tv_sec = CONNECT_TIMEOUT - wait_time;
246 tv.tv_usec = 0;
247
248 ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
249
250 if (ret > 0) {
251 errnosize = sizeof(connect_errno);
252
253 ret = getsockopt(fd, SOL_SOCKET,
254 SO_ERROR, &connect_errno, &errnosize);
255
256 if (ret >= 0 && connect_errno == 0) {
257 /* Connect succeed */
258 goto out;
259 }
260 }
261
262 slept = CONNECT_TIMEOUT;
263 break;
264 case EAGAIN:
265 slept = rand() % 3 + 1;
266 sleep(slept);
267 break;
268 default:
269 goto error_out;
270 }
271
272 }
273
274 out:
275
276 return fd;
277
278 error_out:
279
280 close(fd);
281 return -1;
282}
283
284static const char *winbindd_socket_dir(void)
285{
286#ifdef SOCKET_WRAPPER
287 const char *env_dir;
288
289 env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR);
290 if (env_dir) {
291 return env_dir;
292 }
293#endif
294
295 return WINBINDD_SOCKET_DIR;
296}
297
298/* Connect to winbindd socket */
299
300static int winbind_open_pipe_sock(int recursing, int need_priv)
301{
302#ifdef HAVE_UNIXSOCKET
303 static pid_t our_pid;
304 struct winbindd_request request;
305 struct winbindd_response response;
306 ZERO_STRUCT(request);
307 ZERO_STRUCT(response);
308
309 if (our_pid != getpid()) {
310 winbind_close_sock();
311 our_pid = getpid();
312 }
313
314 if ((need_priv != 0) && (is_privileged == 0)) {
315 winbind_close_sock();
316 }
317
318 if (winbindd_fd != -1) {
319 return winbindd_fd;
320 }
321
322 if (recursing) {
323 return -1;
324 }
325
326 if ((winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir())) == -1) {
327 return -1;
328 }
329
330 is_privileged = 0;
331
332 /* version-check the socket */
333
334 request.wb_flags = WBFLAG_RECURSE;
335 if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
336 winbind_close_sock();
337 return -1;
338 }
339
340 /* try and get priv pipe */
341
342 request.wb_flags = WBFLAG_RECURSE;
343 if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
344 int fd;
345 if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
346 close(winbindd_fd);
347 winbindd_fd = fd;
348 is_privileged = 1;
349 }
350 }
351
352 if ((need_priv != 0) && (is_privileged == 0)) {
353 return -1;
354 }
355
356 SAFE_FREE(response.extra_data.data);
357
358 return winbindd_fd;
359#else
360 return -1;
361#endif /* HAVE_UNIXSOCKET */
362}
363
364/* Write data to winbindd socket */
365
366int winbind_write_sock(void *buffer, int count, int recursing, int need_priv)
367{
368 int result, nwritten;
369
370 /* Open connection to winbind daemon */
371
372 restart:
373
374 if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
375 errno = ENOENT;
376 return -1;
377 }
378
379 /* Write data to socket */
380
381 nwritten = 0;
382
383 while(nwritten < count) {
384 struct timeval tv;
385 fd_set r_fds;
386
387 /* Catch pipe close on other end by checking if a read()
388 call would not block by calling select(). */
389
390 FD_ZERO(&r_fds);
391 FD_SET(winbindd_fd, &r_fds);
392 ZERO_STRUCT(tv);
393
394 if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
395 winbind_close_sock();
396 return -1; /* Select error */
397 }
398
399 /* Write should be OK if fd not available for reading */
400
401 if (!FD_ISSET(winbindd_fd, &r_fds)) {
402
403 /* Do the write */
404
405 result = write(winbindd_fd,
406 (char *)buffer + nwritten,
407 count - nwritten);
408
409 if ((result == -1) || (result == 0)) {
410
411 /* Write failed */
412
413 winbind_close_sock();
414 return -1;
415 }
416
417 nwritten += result;
418
419 } else {
420
421 /* Pipe has closed on remote end */
422
423 winbind_close_sock();
424 goto restart;
425 }
426 }
427
428 return nwritten;
429}
430
431/* Read data from winbindd socket */
432
433int winbind_read_sock(void *buffer, int count)
434{
435 int nread = 0;
436 int total_time = 0, selret;
437
438 if (winbindd_fd == -1) {
439 return -1;
440 }
441
442 /* Read data from socket */
443 while(nread < count) {
444 struct timeval tv;
445 fd_set r_fds;
446
447 /* Catch pipe close on other end by checking if a read()
448 call would not block by calling select(). */
449
450 FD_ZERO(&r_fds);
451 FD_SET(winbindd_fd, &r_fds);
452 ZERO_STRUCT(tv);
453 /* Wait for 5 seconds for a reply. May need to parameterise this... */
454 tv.tv_sec = 5;
455
456 if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
457 winbind_close_sock();
458 return -1; /* Select error */
459 }
460
461 if (selret == 0) {
462 /* Not ready for read yet... */
463 if (total_time >= 30) {
464 /* Timeout */
465 winbind_close_sock();
466 return -1;
467 }
468 total_time += 5;
469 continue;
470 }
471
472 if (FD_ISSET(winbindd_fd, &r_fds)) {
473
474 /* Do the Read */
475
476 int result = read(winbindd_fd, (char *)buffer + nread,
477 count - nread);
478
479 if ((result == -1) || (result == 0)) {
480
481 /* Read failed. I think the only useful thing we
482 can do here is just return -1 and fail since the
483 transaction has failed half way through. */
484
485 winbind_close_sock();
486 return -1;
487 }
488
489 nread += result;
490
491 }
492 }
493
494 return nread;
495}
496
497/* Read reply */
498
499int winbindd_read_reply(struct winbindd_response *response)
500{
501 int result1, result2 = 0;
502
503 if (!response) {
504 return -1;
505 }
506
507 /* Read fixed length response */
508
509 result1 = winbind_read_sock(response,
510 sizeof(struct winbindd_response));
511 if (result1 == -1) {
512 return -1;
513 }
514
515 /* We actually send the pointer value of the extra_data field from
516 the server. This has no meaning in the client's address space
517 so we clear it out. */
518
519 response->extra_data.data = NULL;
520
521 /* Read variable length response */
522
523 if (response->length > sizeof(struct winbindd_response)) {
524 int extra_data_len = response->length -
525 sizeof(struct winbindd_response);
526
527 /* Mallocate memory for extra data */
528
529 if (!(response->extra_data.data = malloc(extra_data_len))) {
530 return -1;
531 }
532
533 result2 = winbind_read_sock(response->extra_data.data,
534 extra_data_len);
535 if (result2 == -1) {
536 winbindd_free_response(response);
537 return -1;
538 }
539 }
540
541 /* Return total amount of data read */
542
543 return result1 + result2;
544}
545
546/*
547 * send simple types of requests
548 */
549
550NSS_STATUS winbindd_send_request(int req_type, int need_priv,
551 struct winbindd_request *request)
552{
553 struct winbindd_request lrequest;
554
555 /* Check for our tricky environment variable */
556
557 if (winbind_env_set()) {
558 return NSS_STATUS_NOTFOUND;
559 }
560
561 if (!request) {
562 ZERO_STRUCT(lrequest);
563 request = &lrequest;
564 }
565
566 /* Fill in request and send down pipe */
567
568 winbindd_init_request(request, req_type);
569
570 if (winbind_write_sock(request, sizeof(*request),
571 request->wb_flags & WBFLAG_RECURSE,
572 need_priv) == -1)
573 {
574 /* Set ENOENT for consistency. Required by some apps */
575 errno = ENOENT;
576
577 return NSS_STATUS_UNAVAIL;
578 }
579
580 if ((request->extra_len != 0) &&
581 (winbind_write_sock(request->extra_data.data,
582 request->extra_len,
583 request->wb_flags & WBFLAG_RECURSE,
584 need_priv) == -1))
585 {
586 /* Set ENOENT for consistency. Required by some apps */
587 errno = ENOENT;
588
589 return NSS_STATUS_UNAVAIL;
590 }
591
592 return NSS_STATUS_SUCCESS;
593}
594
595/*
596 * Get results from winbindd request
597 */
598
599NSS_STATUS winbindd_get_response(struct winbindd_response *response)
600{
601 struct winbindd_response lresponse;
602
603 if (!response) {
604 ZERO_STRUCT(lresponse);
605 response = &lresponse;
606 }
607
608 init_response(response);
609
610 /* Wait for reply */
611 if (winbindd_read_reply(response) == -1) {
612 /* Set ENOENT for consistency. Required by some apps */
613 errno = ENOENT;
614
615 return NSS_STATUS_UNAVAIL;
616 }
617
618 /* Throw away extra data if client didn't request it */
619 if (response == &lresponse) {
620 winbindd_free_response(response);
621 }
622
623 /* Copy reply data from socket */
624 if (response->result != WINBINDD_OK) {
625 return NSS_STATUS_NOTFOUND;
626 }
627
628 return NSS_STATUS_SUCCESS;
629}
630
631/* Handle simple types of requests */
632
633NSS_STATUS winbindd_request_response(int req_type,
634 struct winbindd_request *request,
635 struct winbindd_response *response)
636{
637 NSS_STATUS status = NSS_STATUS_UNAVAIL;
638 int count = 0;
639
640 while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
641 status = winbindd_send_request(req_type, 0, request);
642 if (status != NSS_STATUS_SUCCESS)
643 return(status);
644 status = winbindd_get_response(response);
645 count += 1;
646 }
647
648 return status;
649}
650
651NSS_STATUS winbindd_priv_request_response(int req_type,
652 struct winbindd_request *request,
653 struct winbindd_response *response)
654{
655 NSS_STATUS status = NSS_STATUS_UNAVAIL;
656 int count = 0;
657
658 while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
659 status = winbindd_send_request(req_type, 1, request);
660 if (status != NSS_STATUS_SUCCESS)
661 return(status);
662 status = winbindd_get_response(response);
663 count += 1;
664 }
665
666 return status;
667}
668
669/*************************************************************************
670 ************************************************************************/
671
672const char *nss_err_str(NSS_STATUS ret)
673{
674 switch (ret) {
675 case NSS_STATUS_TRYAGAIN:
676 return "NSS_STATUS_TRYAGAIN";
677 case NSS_STATUS_SUCCESS:
678 return "NSS_STATUS_SUCCESS";
679 case NSS_STATUS_NOTFOUND:
680 return "NSS_STATUS_NOTFOUND";
681 case NSS_STATUS_UNAVAIL:
682 return "NSS_STATUS_UNAVAIL";
683#ifdef NSS_STATUS_RETURN
684 case NSS_STATUS_RETURN:
685 return "NSS_STATUS_RETURN";
686#endif
687 default:
688 return "UNKNOWN RETURN CODE!!!!!!!";
689 }
690}
0691
=== added directory '.pc/security-CVE-2011-0719.patch/source3'
=== added directory '.pc/security-CVE-2011-0719.patch/source3/client'
=== added file '.pc/security-CVE-2011-0719.patch/source3/client/client.c'
--- .pc/security-CVE-2011-0719.patch/source3/client/client.c 1970-01-01 00:00:00 +0000
+++ .pc/security-CVE-2011-0719.patch/source3/client/client.c 2011-03-02 20:47:51 +0000
@@ -0,0 +1,5022 @@
1/*
2 Unix SMB/CIFS implementation.
3 SMB client
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Simo Sorce 2001-2002
6 Copyright (C) Jelmer Vernooij 2003
7 Copyright (C) Gerald (Jerry) Carter 2004
8 Copyright (C) Jeremy Allison 1994-2007
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "includes.h"
25#include "client/client_proto.h"
26#include "include/rpc_client.h"
27#ifndef REGISTER
28#define REGISTER 0
29#endif
30
31extern int do_smb_browse(void); /* mDNS browsing */
32
33extern bool AllowDebugChange;
34extern bool override_logfile;
35extern char tar_type;
36
37static int port = 0;
38static char *service;
39static char *desthost;
40static char *calling_name;
41static bool grepable = false;
42static char *cmdstr = NULL;
43const char *cmd_ptr = NULL;
44
45static int io_bufsize = 524288;
46
47static int name_type = 0x20;
48static int max_protocol = PROTOCOL_NT1;
49
50static int process_tok(char *tok);
51static int cmd_help(void);
52
53#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
54
55/* 30 second timeout on most commands */
56#define CLIENT_TIMEOUT (30*1000)
57#define SHORT_TIMEOUT (5*1000)
58
59/* value for unused fid field in trans2 secondary request */
60#define FID_UNUSED (0xFFFF)
61
62time_t newer_than = 0;
63static int archive_level = 0;
64
65static bool translation = false;
66static bool have_ip;
67
68/* clitar bits insert */
69extern int blocksize;
70extern bool tar_inc;
71extern bool tar_reset;
72/* clitar bits end */
73
74static bool prompt = true;
75
76static bool recurse = false;
77static bool showacls = false;
78bool lowercase = false;
79
80static struct sockaddr_storage dest_ss;
81static char dest_ss_str[INET6_ADDRSTRLEN];
82
83#define SEPARATORS " \t\n\r"
84
85static bool abort_mget = true;
86
87/* timing globals */
88uint64_t get_total_size = 0;
89unsigned int get_total_time_ms = 0;
90static uint64_t put_total_size = 0;
91static unsigned int put_total_time_ms = 0;
92
93/* totals globals */
94static double dir_total;
95
96/* encrypted state. */
97static bool smb_encrypt;
98
99/* root cli_state connection */
100
101struct cli_state *cli;
102
103static char CLI_DIRSEP_CHAR = '\\';
104static char CLI_DIRSEP_STR[] = { '\\', '\0' };
105
106/* Authentication for client connections. */
107struct user_auth_info *auth_info;
108
109/* Accessor functions for directory paths. */
110static char *fileselection;
111static const char *client_get_fileselection(void)
112{
113 if (fileselection) {
114 return fileselection;
115 }
116 return "";
117}
118
119static const char *client_set_fileselection(const char *new_fs)
120{
121 SAFE_FREE(fileselection);
122 if (new_fs) {
123 fileselection = SMB_STRDUP(new_fs);
124 }
125 return client_get_fileselection();
126}
127
128static char *cwd;
129static const char *client_get_cwd(void)
130{
131 if (cwd) {
132 return cwd;
133 }
134 return CLI_DIRSEP_STR;
135}
136
137static const char *client_set_cwd(const char *new_cwd)
138{
139 SAFE_FREE(cwd);
140 if (new_cwd) {
141 cwd = SMB_STRDUP(new_cwd);
142 }
143 return client_get_cwd();
144}
145
146static char *cur_dir;
147const char *client_get_cur_dir(void)
148{
149 if (cur_dir) {
150 return cur_dir;
151 }
152 return CLI_DIRSEP_STR;
153}
154
155const char *client_set_cur_dir(const char *newdir)
156{
157 SAFE_FREE(cur_dir);
158 if (newdir) {
159 cur_dir = SMB_STRDUP(newdir);
160 }
161 return client_get_cur_dir();
162}
163
164/****************************************************************************
165 Write to a local file with CR/LF->LF translation if appropriate. Return the
166 number taken from the buffer. This may not equal the number written.
167****************************************************************************/
168
169static int writefile(int f, char *b, int n)
170{
171 int i;
172
173 if (!translation) {
174 return write(f,b,n);
175 }
176
177 i = 0;
178 while (i < n) {
179 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
180 b++;i++;
181 }
182 if (write(f, b, 1) != 1) {
183 break;
184 }
185 b++;
186 i++;
187 }
188
189 return(i);
190}
191
192/****************************************************************************
193 Read from a file with LF->CR/LF translation if appropriate. Return the
194 number read. read approx n bytes.
195****************************************************************************/
196
197static int readfile(uint8_t *b, int n, XFILE *f)
198{
199 int i;
200 int c;
201
202 if (!translation)
203 return x_fread(b,1,n,f);
204
205 i = 0;
206 while (i < (n - 1) && (i < BUFFER_SIZE)) {
207 if ((c = x_getc(f)) == EOF) {
208 break;
209 }
210
211 if (c == '\n') { /* change all LFs to CR/LF */
212 b[i++] = '\r';
213 }
214
215 b[i++] = c;
216 }
217
218 return(i);
219}
220
221struct push_state {
222 XFILE *f;
223 SMB_OFF_T nread;
224};
225
226static size_t push_source(uint8_t *buf, size_t n, void *priv)
227{
228 struct push_state *state = (struct push_state *)priv;
229 int result;
230
231 if (x_feof(state->f)) {
232 return 0;
233 }
234
235 result = readfile(buf, n, state->f);
236 state->nread += result;
237 return result;
238}
239
240/****************************************************************************
241 Send a message.
242****************************************************************************/
243
244static void send_message(const char *username)
245{
246 int total_len = 0;
247 int grp_id;
248
249 if (!cli_message_start(cli, desthost, username, &grp_id)) {
250 d_printf("message start: %s\n", cli_errstr(cli));
251 return;
252 }
253
254
255 d_printf("Connected. Type your message, ending it with a Control-D\n");
256
257 while (!feof(stdin) && total_len < 1600) {
258 int maxlen = MIN(1600 - total_len,127);
259 char msg[1024];
260 int l=0;
261 int c;
262
263 ZERO_ARRAY(msg);
264
265 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
266 if (c == '\n')
267 msg[l++] = '\r';
268 msg[l] = c;
269 }
270
271 if ((total_len > 0) && (strlen(msg) == 0)) {
272 break;
273 }
274
275 if (!cli_message_text(cli, msg, l, grp_id)) {
276 d_printf("SMBsendtxt failed (%s)\n",cli_errstr(cli));
277 return;
278 }
279
280 total_len += l;
281 }
282
283 if (total_len >= 1600)
284 d_printf("the message was truncated to 1600 bytes\n");
285 else
286 d_printf("sent %d bytes\n",total_len);
287
288 if (!cli_message_end(cli, grp_id)) {
289 d_printf("SMBsendend failed (%s)\n",cli_errstr(cli));
290 return;
291 }
292}
293
294/****************************************************************************
295 Check the space on a device.
296****************************************************************************/
297
298static int do_dskattr(void)
299{
300 int total, bsize, avail;
301 struct cli_state *targetcli = NULL;
302 char *targetpath = NULL;
303 TALLOC_CTX *ctx = talloc_tos();
304
305 if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
306 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
307 return 1;
308 }
309
310 if (!cli_dskattr(targetcli, &bsize, &total, &avail)) {
311 d_printf("Error in dskattr: %s\n",cli_errstr(targetcli));
312 return 1;
313 }
314
315 d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
316 total, bsize, avail);
317
318 return 0;
319}
320
321/****************************************************************************
322 Show cd/pwd.
323****************************************************************************/
324
325static int cmd_pwd(void)
326{
327 d_printf("Current directory is %s",service);
328 d_printf("%s\n",client_get_cur_dir());
329 return 0;
330}
331
332/****************************************************************************
333 Ensure name has correct directory separators.
334****************************************************************************/
335
336static void normalize_name(char *newdir)
337{
338 if (!(cli->posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
339 string_replace(newdir,'/','\\');
340 }
341}
342
343/****************************************************************************
344 Change directory - inner section.
345****************************************************************************/
346
347static int do_cd(const char *new_dir)
348{
349 char *newdir = NULL;
350 char *saved_dir = NULL;
351 char *new_cd = NULL;
352 char *targetpath = NULL;
353 struct cli_state *targetcli = NULL;
354 SMB_STRUCT_STAT sbuf;
355 uint32 attributes;
356 int ret = 1;
357 TALLOC_CTX *ctx = talloc_stackframe();
358
359 newdir = talloc_strdup(ctx, new_dir);
360 if (!newdir) {
361 TALLOC_FREE(ctx);
362 return 1;
363 }
364
365 normalize_name(newdir);
366
367 /* Save the current directory in case the new directory is invalid */
368
369 saved_dir = talloc_strdup(ctx, client_get_cur_dir());
370 if (!saved_dir) {
371 TALLOC_FREE(ctx);
372 return 1;
373 }
374
375 if (*newdir == CLI_DIRSEP_CHAR) {
376 client_set_cur_dir(newdir);
377 new_cd = newdir;
378 } else {
379 new_cd = talloc_asprintf(ctx, "%s%s",
380 client_get_cur_dir(),
381 newdir);
382 if (!new_cd) {
383 goto out;
384 }
385 }
386
387 /* Ensure cur_dir ends in a DIRSEP */
388 if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
389 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
390 if (!new_cd) {
391 goto out;
392 }
393 }
394 client_set_cur_dir(new_cd);
395
396 new_cd = clean_name(ctx, new_cd);
397 client_set_cur_dir(new_cd);
398
399 if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
400 d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
401 client_set_cur_dir(saved_dir);
402 goto out;
403 }
404
405 if (strequal(targetpath,CLI_DIRSEP_STR )) {
406 TALLOC_FREE(ctx);
407 return 0;
408 }
409
410 /* Use a trans2_qpathinfo to test directories for modern servers.
411 Except Win9x doesn't support the qpathinfo_basic() call..... */
412
413 if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
414 if (!cli_qpathinfo_basic( targetcli, targetpath, &sbuf, &attributes ) ) {
415 d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
416 client_set_cur_dir(saved_dir);
417 goto out;
418 }
419
420 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
421 d_printf("cd %s: not a directory\n", new_cd);
422 client_set_cur_dir(saved_dir);
423 goto out;
424 }
425 } else {
426 targetpath = talloc_asprintf(ctx,
427 "%s%s",
428 targetpath,
429 CLI_DIRSEP_STR );
430 if (!targetpath) {
431 client_set_cur_dir(saved_dir);
432 goto out;
433 }
434 targetpath = clean_name(ctx, targetpath);
435 if (!targetpath) {
436 client_set_cur_dir(saved_dir);
437 goto out;
438 }
439
440 if (!cli_chkpath(targetcli, targetpath)) {
441 d_printf("cd %s: %s\n", new_cd, cli_errstr(targetcli));
442 client_set_cur_dir(saved_dir);
443 goto out;
444 }
445 }
446
447 ret = 0;
448
449out:
450
451 TALLOC_FREE(ctx);
452 return ret;
453}
454
455/****************************************************************************
456 Change directory.
457****************************************************************************/
458
459static int cmd_cd(void)
460{
461 char *buf = NULL;
462 int rc = 0;
463
464 if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
465 rc = do_cd(buf);
466 } else {
467 d_printf("Current directory is %s\n",client_get_cur_dir());
468 }
469
470 return rc;
471}
472
473/****************************************************************************
474 Change directory.
475****************************************************************************/
476
477static int cmd_cd_oneup(void)
478{
479 return do_cd("..");
480}
481
482/*******************************************************************
483 Decide if a file should be operated on.
484********************************************************************/
485
486static bool do_this_one(file_info *finfo)
487{
488 if (!finfo->name) {
489 return false;
490 }
491
492 if (finfo->mode & aDIR) {
493 return true;
494 }
495
496 if (*client_get_fileselection() &&
497 !mask_match(finfo->name,client_get_fileselection(),false)) {
498 DEBUG(3,("mask_match %s failed\n", finfo->name));
499 return false;
500 }
501
502 if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
503 DEBUG(3,("newer_than %s failed\n", finfo->name));
504 return false;
505 }
506
507 if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
508 DEBUG(3,("archive %s failed\n", finfo->name));
509 return false;
510 }
511
512 return true;
513}
514
515/****************************************************************************
516 Display info about a file.
517****************************************************************************/
518
519static void display_finfo(file_info *finfo, const char *dir)
520{
521 time_t t;
522 TALLOC_CTX *ctx = talloc_tos();
523
524 if (!do_this_one(finfo)) {
525 return;
526 }
527
528 t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
529 if (!showacls) {
530 d_printf(" %-30s%7.7s %8.0f %s",
531 finfo->name,
532 attrib_string(finfo->mode),
533 (double)finfo->size,
534 time_to_asc(t));
535 dir_total += finfo->size;
536 } else {
537 char *afname = NULL;
538 int fnum;
539
540 /* skip if this is . or .. */
541 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
542 return;
543 /* create absolute filename for cli_nt_create() FIXME */
544 afname = talloc_asprintf(ctx,
545 "%s%s%s",
546 dir,
547 CLI_DIRSEP_STR,
548 finfo->name);
549 if (!afname) {
550 return;
551 }
552 /* print file meta date header */
553 d_printf( "FILENAME:%s\n", finfo->name);
554 d_printf( "MODE:%s\n", attrib_string(finfo->mode));
555 d_printf( "SIZE:%.0f\n", (double)finfo->size);
556 d_printf( "MTIME:%s", time_to_asc(t));
557 fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
558 if (fnum == -1) {
559 DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
560 afname,
561 cli_errstr( finfo->cli)));
562 } else {
563 SEC_DESC *sd = NULL;
564 sd = cli_query_secdesc(finfo->cli, fnum, ctx);
565 if (!sd) {
566 DEBUG( 0, ("display_finfo() failed to "
567 "get security descriptor: %s",
568 cli_errstr( finfo->cli)));
569 } else {
570 display_sec_desc(sd);
571 }
572 TALLOC_FREE(sd);
573 }
574 TALLOC_FREE(afname);
575 }
576}
577
578/****************************************************************************
579 Accumulate size of a file.
580****************************************************************************/
581
582static void do_du(file_info *finfo, const char *dir)
583{
584 if (do_this_one(finfo)) {
585 dir_total += finfo->size;
586 }
587}
588
589static bool do_list_recurse;
590static bool do_list_dirs;
591static char *do_list_queue = 0;
592static long do_list_queue_size = 0;
593static long do_list_queue_start = 0;
594static long do_list_queue_end = 0;
595static void (*do_list_fn)(file_info *, const char *dir);
596
597/****************************************************************************
598 Functions for do_list_queue.
599****************************************************************************/
600
601/*
602 * The do_list_queue is a NUL-separated list of strings stored in a
603 * char*. Since this is a FIFO, we keep track of the beginning and
604 * ending locations of the data in the queue. When we overflow, we
605 * double the size of the char*. When the start of the data passes
606 * the midpoint, we move everything back. This is logically more
607 * complex than a linked list, but easier from a memory management
608 * angle. In any memory error condition, do_list_queue is reset.
609 * Functions check to ensure that do_list_queue is non-NULL before
610 * accessing it.
611 */
612
613static void reset_do_list_queue(void)
614{
615 SAFE_FREE(do_list_queue);
616 do_list_queue_size = 0;
617 do_list_queue_start = 0;
618 do_list_queue_end = 0;
619}
620
621static void init_do_list_queue(void)
622{
623 reset_do_list_queue();
624 do_list_queue_size = 1024;
625 do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
626 if (do_list_queue == 0) {
627 d_printf("malloc fail for size %d\n",
628 (int)do_list_queue_size);
629 reset_do_list_queue();
630 } else {
631 memset(do_list_queue, 0, do_list_queue_size);
632 }
633}
634
635static void adjust_do_list_queue(void)
636{
637 /*
638 * If the starting point of the queue is more than half way through,
639 * move everything toward the beginning.
640 */
641
642 if (do_list_queue == NULL) {
643 DEBUG(4,("do_list_queue is empty\n"));
644 do_list_queue_start = do_list_queue_end = 0;
645 return;
646 }
647
648 if (do_list_queue_start == do_list_queue_end) {
649 DEBUG(4,("do_list_queue is empty\n"));
650 do_list_queue_start = do_list_queue_end = 0;
651 *do_list_queue = '\0';
652 } else if (do_list_queue_start > (do_list_queue_size / 2)) {
653 DEBUG(4,("sliding do_list_queue backward\n"));
654 memmove(do_list_queue,
655 do_list_queue + do_list_queue_start,
656 do_list_queue_end - do_list_queue_start);
657 do_list_queue_end -= do_list_queue_start;
658 do_list_queue_start = 0;
659 }
660}
661
662static void add_to_do_list_queue(const char *entry)
663{
664 long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
665 while (new_end > do_list_queue_size) {
666 do_list_queue_size *= 2;
667 DEBUG(4,("enlarging do_list_queue to %d\n",
668 (int)do_list_queue_size));
669 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
670 if (! do_list_queue) {
671 d_printf("failure enlarging do_list_queue to %d bytes\n",
672 (int)do_list_queue_size);
673 reset_do_list_queue();
674 } else {
675 memset(do_list_queue + do_list_queue_size / 2,
676 0, do_list_queue_size / 2);
677 }
678 }
679 if (do_list_queue) {
680 safe_strcpy_base(do_list_queue + do_list_queue_end,
681 entry, do_list_queue, do_list_queue_size);
682 do_list_queue_end = new_end;
683 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
684 entry, (int)do_list_queue_start, (int)do_list_queue_end));
685 }
686}
687
688static char *do_list_queue_head(void)
689{
690 return do_list_queue + do_list_queue_start;
691}
692
693static void remove_do_list_queue_head(void)
694{
695 if (do_list_queue_end > do_list_queue_start) {
696 do_list_queue_start += strlen(do_list_queue_head()) + 1;
697 adjust_do_list_queue();
698 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
699 (int)do_list_queue_start, (int)do_list_queue_end));
700 }
701}
702
703static int do_list_queue_empty(void)
704{
705 return (! (do_list_queue && *do_list_queue));
706}
707
708/****************************************************************************
709 A helper for do_list.
710****************************************************************************/
711
712static void do_list_helper(const char *mntpoint, file_info *f, const char *mask, void *state)
713{
714 TALLOC_CTX *ctx = talloc_tos();
715 char *dir = NULL;
716 char *dir_end = NULL;
717
718 /* Work out the directory. */
719 dir = talloc_strdup(ctx, mask);
720 if (!dir) {
721 return;
722 }
723 if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
724 *dir_end = '\0';
725 }
726
727 if (f->mode & aDIR) {
728 if (do_list_dirs && do_this_one(f)) {
729 do_list_fn(f, dir);
730 }
731 if (do_list_recurse &&
732 f->name &&
733 !strequal(f->name,".") &&
734 !strequal(f->name,"..")) {
735 char *mask2 = NULL;
736 char *p = NULL;
737
738 if (!f->name[0]) {
739 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
740 TALLOC_FREE(dir);
741 return;
742 }
743
744 mask2 = talloc_asprintf(ctx,
745 "%s%s",
746 mntpoint,
747 mask);
748 if (!mask2) {
749 TALLOC_FREE(dir);
750 return;
751 }
752 p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
753 if (p) {
754 p[1] = 0;
755 } else {
756 mask2[0] = '\0';
757 }
758 mask2 = talloc_asprintf_append(mask2,
759 "%s%s*",
760 f->name,
761 CLI_DIRSEP_STR);
762 if (!mask2) {
763 TALLOC_FREE(dir);
764 return;
765 }
766 add_to_do_list_queue(mask2);
767 TALLOC_FREE(mask2);
768 }
769 TALLOC_FREE(dir);
770 return;
771 }
772
773 if (do_this_one(f)) {
774 do_list_fn(f,dir);
775 }
776 TALLOC_FREE(dir);
777}
778
779/****************************************************************************
780 A wrapper around cli_list that adds recursion.
781****************************************************************************/
782
783void do_list(const char *mask,
784 uint16 attribute,
785 void (*fn)(file_info *, const char *dir),
786 bool rec,
787 bool dirs)
788{
789 static int in_do_list = 0;
790 TALLOC_CTX *ctx = talloc_tos();
791 struct cli_state *targetcli = NULL;
792 char *targetpath = NULL;
793
794 if (in_do_list && rec) {
795 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
796 exit(1);
797 }
798
799 in_do_list = 1;
800
801 do_list_recurse = rec;
802 do_list_dirs = dirs;
803 do_list_fn = fn;
804
805 if (rec) {
806 init_do_list_queue();
807 add_to_do_list_queue(mask);
808
809 while (!do_list_queue_empty()) {
810 /*
811 * Need to copy head so that it doesn't become
812 * invalid inside the call to cli_list. This
813 * would happen if the list were expanded
814 * during the call.
815 * Fix from E. Jay Berkenbilt (ejb@ql.org)
816 */
817 char *head = talloc_strdup(ctx, do_list_queue_head());
818
819 if (!head) {
820 return;
821 }
822
823 /* check for dfs */
824
825 if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
826 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
827 remove_do_list_queue_head();
828 continue;
829 }
830
831 cli_list(targetcli, targetpath, attribute, do_list_helper, NULL);
832 remove_do_list_queue_head();
833 if ((! do_list_queue_empty()) && (fn == display_finfo)) {
834 char *next_file = do_list_queue_head();
835 char *save_ch = 0;
836 if ((strlen(next_file) >= 2) &&
837 (next_file[strlen(next_file) - 1] == '*') &&
838 (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
839 save_ch = next_file +
840 strlen(next_file) - 2;
841 *save_ch = '\0';
842 if (showacls) {
843 /* cwd is only used if showacls is on */
844 client_set_cwd(next_file);
845 }
846 }
847 if (!showacls) /* don't disturbe the showacls output */
848 d_printf("\n%s\n",next_file);
849 if (save_ch) {
850 *save_ch = CLI_DIRSEP_CHAR;
851 }
852 }
853 TALLOC_FREE(head);
854 TALLOC_FREE(targetpath);
855 }
856 } else {
857 /* check for dfs */
858 if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
859 if (cli_list(targetcli, targetpath, attribute, do_list_helper, NULL) == -1) {
860 d_printf("%s listing %s\n",
861 cli_errstr(targetcli), targetpath);
862 }
863 TALLOC_FREE(targetpath);
864 } else {
865 d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
866 }
867 }
868
869 in_do_list = 0;
870 reset_do_list_queue();
871}
872
873/****************************************************************************
874 Get a directory listing.
875****************************************************************************/
876
877static int cmd_dir(void)
878{
879 TALLOC_CTX *ctx = talloc_tos();
880 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
881 char *mask = NULL;
882 char *buf = NULL;
883 int rc = 1;
884
885 dir_total = 0;
886 mask = talloc_strdup(ctx, client_get_cur_dir());
887 if (!mask) {
888 return 1;
889 }
890
891 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
892 normalize_name(buf);
893 if (*buf == CLI_DIRSEP_CHAR) {
894 mask = talloc_strdup(ctx, buf);
895 } else {
896 mask = talloc_asprintf_append(mask, "%s", buf);
897 }
898 } else {
899 mask = talloc_asprintf_append(mask, "*");
900 }
901 if (!mask) {
902 return 1;
903 }
904
905 if (showacls) {
906 /* cwd is only used if showacls is on */
907 client_set_cwd(client_get_cur_dir());
908 }
909
910 do_list(mask, attribute, display_finfo, recurse, true);
911
912 rc = do_dskattr();
913
914 DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
915
916 return rc;
917}
918
919/****************************************************************************
920 Get a directory listing.
921****************************************************************************/
922
923static int cmd_du(void)
924{
925 TALLOC_CTX *ctx = talloc_tos();
926 uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
927 char *mask = NULL;
928 char *buf = NULL;
929 int rc = 1;
930
931 dir_total = 0;
932 mask = talloc_strdup(ctx, client_get_cur_dir());
933 if (!mask) {
934 return 1;
935 }
936 if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
937 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
938 if (!mask) {
939 return 1;
940 }
941 }
942
943 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
944 normalize_name(buf);
945 if (*buf == CLI_DIRSEP_CHAR) {
946 mask = talloc_strdup(ctx, buf);
947 } else {
948 mask = talloc_asprintf_append(mask, "%s", buf);
949 }
950 } else {
951 mask = talloc_strdup(ctx, "*");
952 }
953
954 do_list(mask, attribute, do_du, recurse, true);
955
956 rc = do_dskattr();
957
958 d_printf("Total number of bytes: %.0f\n", dir_total);
959
960 return rc;
961}
962
963static int cmd_echo(void)
964{
965 TALLOC_CTX *ctx = talloc_tos();
966 char *num;
967 char *data;
968 NTSTATUS status;
969
970 if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
971 || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
972 d_printf("echo <num> <data>\n");
973 return 1;
974 }
975
976 status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
977
978 if (!NT_STATUS_IS_OK(status)) {
979 d_printf("echo failed: %s\n", nt_errstr(status));
980 return 1;
981 }
982
983 return 0;
984}
985
986/****************************************************************************
987 Get a file from rname to lname
988****************************************************************************/
989
990static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
991{
992 int *pfd = (int *)priv;
993 if (writefile(*pfd, buf, n) == -1) {
994 return map_nt_error_from_unix(errno);
995 }
996 return NT_STATUS_OK;
997}
998
999static int do_get(const char *rname, const char *lname_in, bool reget)
1000{
1001 TALLOC_CTX *ctx = talloc_tos();
1002 int handle = 0, fnum;
1003 bool newhandle = false;
1004 struct timeval tp_start;
1005 uint16 attr;
1006 SMB_OFF_T size;
1007 off_t start = 0;
1008 SMB_OFF_T nread = 0;
1009 int rc = 0;
1010 struct cli_state *targetcli = NULL;
1011 char *targetname = NULL;
1012 char *lname = NULL;
1013 NTSTATUS status;
1014
1015 lname = talloc_strdup(ctx, lname_in);
1016 if (!lname) {
1017 return 1;
1018 }
1019
1020 if (lowercase) {
1021 strlower_m(lname);
1022 }
1023
1024 if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
1025 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1026 return 1;
1027 }
1028
1029 GetTimeOfDay(&tp_start);
1030
1031 fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
1032
1033 if (fnum == -1) {
1034 d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
1035 return 1;
1036 }
1037
1038 if(!strcmp(lname,"-")) {
1039 handle = fileno(stdout);
1040 } else {
1041 if (reget) {
1042 handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
1043 if (handle >= 0) {
1044 start = sys_lseek(handle, 0, SEEK_END);
1045 if (start == -1) {
1046 d_printf("Error seeking local file\n");
1047 return 1;
1048 }
1049 }
1050 } else {
1051 handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1052 }
1053 newhandle = true;
1054 }
1055 if (handle < 0) {
1056 d_printf("Error opening local file %s\n",lname);
1057 return 1;
1058 }
1059
1060
1061 if (!cli_qfileinfo(targetcli, fnum,
1062 &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
1063 !cli_getattrE(targetcli, fnum,
1064 &attr, &size, NULL, NULL, NULL)) {
1065 d_printf("getattrib: %s\n",cli_errstr(targetcli));
1066 return 1;
1067 }
1068
1069 DEBUG(1,("getting file %s of size %.0f as %s ",
1070 rname, (double)size, lname));
1071
1072 status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1073 writefile_sink, (void *)&handle, &nread);
1074 if (!NT_STATUS_IS_OK(status)) {
1075 d_fprintf(stderr, "parallel_read returned %s\n",
1076 nt_errstr(status));
1077 cli_close(targetcli, fnum);
1078 return 1;
1079 }
1080
1081 if (!cli_close(targetcli, fnum)) {
1082 d_printf("Error %s closing remote file\n",cli_errstr(cli));
1083 rc = 1;
1084 }
1085
1086 if (newhandle) {
1087 close(handle);
1088 }
1089
1090 if (archive_level >= 2 && (attr & aARCH)) {
1091 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
1092 }
1093
1094 {
1095 struct timeval tp_end;
1096 int this_time;
1097
1098 GetTimeOfDay(&tp_end);
1099 this_time =
1100 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1101 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1102 get_total_time_ms += this_time;
1103 get_total_size += nread;
1104
1105 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1106 nread / (1.024*this_time + 1.0e-4),
1107 get_total_size / (1.024*get_total_time_ms)));
1108 }
1109
1110 TALLOC_FREE(targetname);
1111 return rc;
1112}
1113
1114/****************************************************************************
1115 Get a file.
1116****************************************************************************/
1117
1118static int cmd_get(void)
1119{
1120 TALLOC_CTX *ctx = talloc_tos();
1121 char *lname = NULL;
1122 char *rname = NULL;
1123 char *fname = NULL;
1124
1125 rname = talloc_strdup(ctx, client_get_cur_dir());
1126 if (!rname) {
1127 return 1;
1128 }
1129
1130 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1131 d_printf("get <filename> [localname]\n");
1132 return 1;
1133 }
1134 rname = talloc_asprintf_append(rname, "%s", fname);
1135 if (!rname) {
1136 return 1;
1137 }
1138 rname = clean_name(ctx, rname);
1139 if (!rname) {
1140 return 1;
1141 }
1142
1143 next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1144 if (!lname) {
1145 lname = fname;
1146 }
1147
1148 return do_get(rname, lname, false);
1149}
1150
1151/****************************************************************************
1152 Do an mget operation on one file.
1153****************************************************************************/
1154
1155static void do_mget(file_info *finfo, const char *dir)
1156{
1157 TALLOC_CTX *ctx = talloc_tos();
1158 char *rname = NULL;
1159 char *quest = NULL;
1160 char *saved_curdir = NULL;
1161 char *mget_mask = NULL;
1162 char *new_cd = NULL;
1163
1164 if (!finfo->name) {
1165 return;
1166 }
1167
1168 if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1169 return;
1170
1171 if (abort_mget) {
1172 d_printf("mget aborted\n");
1173 return;
1174 }
1175
1176 if (finfo->mode & aDIR) {
1177 if (asprintf(&quest,
1178 "Get directory %s? ",finfo->name) < 0) {
1179 return;
1180 }
1181 } else {
1182 if (asprintf(&quest,
1183 "Get file %s? ",finfo->name) < 0) {
1184 return;
1185 }
1186 }
1187
1188 if (prompt && !yesno(quest)) {
1189 SAFE_FREE(quest);
1190 return;
1191 }
1192 SAFE_FREE(quest);
1193
1194 if (!(finfo->mode & aDIR)) {
1195 rname = talloc_asprintf(ctx,
1196 "%s%s",
1197 client_get_cur_dir(),
1198 finfo->name);
1199 if (!rname) {
1200 return;
1201 }
1202 do_get(rname, finfo->name, false);
1203 TALLOC_FREE(rname);
1204 return;
1205 }
1206
1207 /* handle directories */
1208 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1209 if (!saved_curdir) {
1210 return;
1211 }
1212
1213 new_cd = talloc_asprintf(ctx,
1214 "%s%s%s",
1215 client_get_cur_dir(),
1216 finfo->name,
1217 CLI_DIRSEP_STR);
1218 if (!new_cd) {
1219 return;
1220 }
1221 client_set_cur_dir(new_cd);
1222
1223 string_replace(finfo->name,'\\','/');
1224 if (lowercase) {
1225 strlower_m(finfo->name);
1226 }
1227
1228 if (!directory_exist(finfo->name) &&
1229 mkdir(finfo->name,0777) != 0) {
1230 d_printf("failed to create directory %s\n",finfo->name);
1231 client_set_cur_dir(saved_curdir);
1232 return;
1233 }
1234
1235 if (chdir(finfo->name) != 0) {
1236 d_printf("failed to chdir to directory %s\n",finfo->name);
1237 client_set_cur_dir(saved_curdir);
1238 return;
1239 }
1240
1241 mget_mask = talloc_asprintf(ctx,
1242 "%s*",
1243 client_get_cur_dir());
1244
1245 if (!mget_mask) {
1246 return;
1247 }
1248
1249 do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
1250 if (chdir("..") == -1) {
1251 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1252 strerror(errno) );
1253 }
1254 client_set_cur_dir(saved_curdir);
1255 TALLOC_FREE(mget_mask);
1256 TALLOC_FREE(saved_curdir);
1257 TALLOC_FREE(new_cd);
1258}
1259
1260/****************************************************************************
1261 View the file using the pager.
1262****************************************************************************/
1263
1264static int cmd_more(void)
1265{
1266 TALLOC_CTX *ctx = talloc_tos();
1267 char *rname = NULL;
1268 char *fname = NULL;
1269 char *lname = NULL;
1270 char *pager_cmd = NULL;
1271 const char *pager;
1272 int fd;
1273 int rc = 0;
1274
1275 rname = talloc_strdup(ctx, client_get_cur_dir());
1276 if (!rname) {
1277 return 1;
1278 }
1279
1280 lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1281 if (!lname) {
1282 return 1;
1283 }
1284 fd = smb_mkstemp(lname);
1285 if (fd == -1) {
1286 d_printf("failed to create temporary file for more\n");
1287 return 1;
1288 }
1289 close(fd);
1290
1291 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1292 d_printf("more <filename>\n");
1293 unlink(lname);
1294 return 1;
1295 }
1296 rname = talloc_asprintf_append(rname, "%s", fname);
1297 if (!rname) {
1298 return 1;
1299 }
1300 rname = clean_name(ctx,rname);
1301 if (!rname) {
1302 return 1;
1303 }
1304
1305 rc = do_get(rname, lname, false);
1306
1307 pager=getenv("PAGER");
1308
1309 pager_cmd = talloc_asprintf(ctx,
1310 "%s %s",
1311 (pager? pager:PAGER),
1312 lname);
1313 if (!pager_cmd) {
1314 return 1;
1315 }
1316 if (system(pager_cmd) == -1) {
1317 d_printf("system command '%s' returned -1\n",
1318 pager_cmd);
1319 }
1320 unlink(lname);
1321
1322 return rc;
1323}
1324
1325/****************************************************************************
1326 Do a mget command.
1327****************************************************************************/
1328
1329static int cmd_mget(void)
1330{
1331 TALLOC_CTX *ctx = talloc_tos();
1332 uint16 attribute = aSYSTEM | aHIDDEN;
1333 char *mget_mask = NULL;
1334 char *buf = NULL;
1335
1336 if (recurse) {
1337 attribute |= aDIR;
1338 }
1339
1340 abort_mget = false;
1341
1342 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1343 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1344 if (!mget_mask) {
1345 return 1;
1346 }
1347 if (*buf == CLI_DIRSEP_CHAR) {
1348 mget_mask = talloc_strdup(ctx, buf);
1349 } else {
1350 mget_mask = talloc_asprintf_append(mget_mask,
1351 "%s", buf);
1352 }
1353 if (!mget_mask) {
1354 return 1;
1355 }
1356 do_list(mget_mask, attribute, do_mget, false, true);
1357 }
1358
1359 if (mget_mask == NULL) {
1360 d_printf("nothing to mget\n");
1361 return 0;
1362 }
1363
1364 if (!*mget_mask) {
1365 mget_mask = talloc_asprintf(ctx,
1366 "%s*",
1367 client_get_cur_dir());
1368 if (!mget_mask) {
1369 return 1;
1370 }
1371 do_list(mget_mask, attribute, do_mget, false, true);
1372 }
1373
1374 return 0;
1375}
1376
1377/****************************************************************************
1378 Make a directory of name "name".
1379****************************************************************************/
1380
1381static bool do_mkdir(const char *name)
1382{
1383 TALLOC_CTX *ctx = talloc_tos();
1384 struct cli_state *targetcli;
1385 char *targetname = NULL;
1386
1387 if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
1388 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1389 return false;
1390 }
1391
1392 if (!cli_mkdir(targetcli, targetname)) {
1393 d_printf("%s making remote directory %s\n",
1394 cli_errstr(targetcli),name);
1395 return false;
1396 }
1397
1398 return true;
1399}
1400
1401/****************************************************************************
1402 Show 8.3 name of a file.
1403****************************************************************************/
1404
1405static bool do_altname(const char *name)
1406{
1407 fstring altname;
1408
1409 if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1410 d_printf("%s getting alt name for %s\n",
1411 cli_errstr(cli),name);
1412 return false;
1413 }
1414 d_printf("%s\n", altname);
1415
1416 return true;
1417}
1418
1419/****************************************************************************
1420 Exit client.
1421****************************************************************************/
1422
1423static int cmd_quit(void)
1424{
1425 cli_shutdown(cli);
1426 exit(0);
1427 /* NOTREACHED */
1428 return 0;
1429}
1430
1431/****************************************************************************
1432 Make a directory.
1433****************************************************************************/
1434
1435static int cmd_mkdir(void)
1436{
1437 TALLOC_CTX *ctx = talloc_tos();
1438 char *mask = NULL;
1439 char *buf = NULL;
1440
1441 mask = talloc_strdup(ctx, client_get_cur_dir());
1442 if (!mask) {
1443 return 1;
1444 }
1445
1446 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1447 if (!recurse) {
1448 d_printf("mkdir <dirname>\n");
1449 }
1450 return 1;
1451 }
1452 mask = talloc_asprintf_append(mask, "%s", buf);
1453 if (!mask) {
1454 return 1;
1455 }
1456
1457 if (recurse) {
1458 char *ddir = NULL;
1459 char *ddir2 = NULL;
1460 struct cli_state *targetcli;
1461 char *targetname = NULL;
1462 char *p = NULL;
1463 char *saveptr;
1464
1465 ddir2 = talloc_strdup(ctx, "");
1466 if (!ddir2) {
1467 return 1;
1468 }
1469
1470 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
1471 return 1;
1472 }
1473
1474 ddir = talloc_strdup(ctx, targetname);
1475 if (!ddir) {
1476 return 1;
1477 }
1478 trim_char(ddir,'.','\0');
1479 p = strtok_r(ddir, "/\\", &saveptr);
1480 while (p) {
1481 ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1482 if (!ddir2) {
1483 return 1;
1484 }
1485 if (!cli_chkpath(targetcli, ddir2)) {
1486 do_mkdir(ddir2);
1487 }
1488 ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1489 if (!ddir2) {
1490 return 1;
1491 }
1492 p = strtok_r(NULL, "/\\", &saveptr);
1493 }
1494 } else {
1495 do_mkdir(mask);
1496 }
1497
1498 return 0;
1499}
1500
1501/****************************************************************************
1502 Show alt name.
1503****************************************************************************/
1504
1505static int cmd_altname(void)
1506{
1507 TALLOC_CTX *ctx = talloc_tos();
1508 char *name;
1509 char *buf;
1510
1511 name = talloc_strdup(ctx, client_get_cur_dir());
1512 if (!name) {
1513 return 1;
1514 }
1515
1516 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1517 d_printf("altname <file>\n");
1518 return 1;
1519 }
1520 name = talloc_asprintf_append(name, "%s", buf);
1521 if (!name) {
1522 return 1;
1523 }
1524 do_altname(name);
1525 return 0;
1526}
1527
1528/****************************************************************************
1529 Show all info we can get
1530****************************************************************************/
1531
1532static int do_allinfo(const char *name)
1533{
1534 fstring altname;
1535 struct timespec b_time, a_time, m_time, c_time;
1536 SMB_OFF_T size;
1537 uint16_t mode;
1538 SMB_INO_T ino;
1539 NTTIME tmp;
1540 unsigned int num_streams;
1541 struct stream_struct *streams;
1542 unsigned int i;
1543
1544 if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
1545 d_printf("%s getting alt name for %s\n",
1546 cli_errstr(cli),name);
1547 return false;
1548 }
1549 d_printf("altname: %s\n", altname);
1550
1551 if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
1552 &size, &mode, &ino)) {
1553 d_printf("%s getting pathinfo for %s\n",
1554 cli_errstr(cli),name);
1555 return false;
1556 }
1557
1558 unix_timespec_to_nt_time(&tmp, b_time);
1559 d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
1560
1561 unix_timespec_to_nt_time(&tmp, a_time);
1562 d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
1563
1564 unix_timespec_to_nt_time(&tmp, m_time);
1565 d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
1566
1567 unix_timespec_to_nt_time(&tmp, c_time);
1568 d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
1569
1570 if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1571 &streams)) {
1572 d_printf("%s getting streams for %s\n",
1573 cli_errstr(cli),name);
1574 return false;
1575 }
1576
1577 for (i=0; i<num_streams; i++) {
1578 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1579 (unsigned long long)streams[i].size);
1580 }
1581
1582 return 0;
1583}
1584
1585/****************************************************************************
1586 Show all info we can get
1587****************************************************************************/
1588
1589static int cmd_allinfo(void)
1590{
1591 TALLOC_CTX *ctx = talloc_tos();
1592 char *name;
1593 char *buf;
1594
1595 name = talloc_strdup(ctx, client_get_cur_dir());
1596 if (!name) {
1597 return 1;
1598 }
1599
1600 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1601 d_printf("allinfo <file>\n");
1602 return 1;
1603 }
1604 name = talloc_asprintf_append(name, "%s", buf);
1605 if (!name) {
1606 return 1;
1607 }
1608
1609 do_allinfo(name);
1610
1611 return 0;
1612}
1613
1614/****************************************************************************
1615 Put a single file.
1616****************************************************************************/
1617
1618static int do_put(const char *rname, const char *lname, bool reput)
1619{
1620 TALLOC_CTX *ctx = talloc_tos();
1621 int fnum;
1622 XFILE *f;
1623 SMB_OFF_T start = 0;
1624 int rc = 0;
1625 struct timeval tp_start;
1626 struct cli_state *targetcli;
1627 char *targetname = NULL;
1628 struct push_state state;
1629 NTSTATUS status;
1630
1631 if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
1632 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1633 return 1;
1634 }
1635
1636 GetTimeOfDay(&tp_start);
1637
1638 if (reput) {
1639 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
1640 if (fnum >= 0) {
1641 if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
1642 !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
1643 d_printf("getattrib: %s\n",cli_errstr(cli));
1644 return 1;
1645 }
1646 }
1647 } else {
1648 fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
1649 }
1650
1651 if (fnum == -1) {
1652 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1653 return 1;
1654 }
1655
1656 /* allow files to be piped into smbclient
1657 jdblair 24.jun.98
1658
1659 Note that in this case this function will exit(0) rather
1660 than returning. */
1661 if (!strcmp(lname, "-")) {
1662 f = x_stdin;
1663 /* size of file is not known */
1664 } else {
1665 f = x_fopen(lname,O_RDONLY, 0);
1666 if (f && reput) {
1667 if (x_tseek(f, start, SEEK_SET) == -1) {
1668 d_printf("Error seeking local file\n");
1669 return 1;
1670 }
1671 }
1672 }
1673
1674 if (!f) {
1675 d_printf("Error opening local file %s\n",lname);
1676 return 1;
1677 }
1678
1679 DEBUG(1,("putting file %s as %s ",lname,
1680 rname));
1681
1682 x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
1683
1684 state.f = f;
1685 state.nread = 0;
1686
1687 status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
1688 &state);
1689 if (!NT_STATUS_IS_OK(status)) {
1690 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1691 }
1692
1693 if (!cli_close(targetcli, fnum)) {
1694 d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
1695 x_fclose(f);
1696 return 1;
1697 }
1698
1699 if (f != x_stdin) {
1700 x_fclose(f);
1701 }
1702
1703 {
1704 struct timeval tp_end;
1705 int this_time;
1706
1707 GetTimeOfDay(&tp_end);
1708 this_time =
1709 (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1710 (tp_end.tv_usec - tp_start.tv_usec)/1000;
1711 put_total_time_ms += this_time;
1712 put_total_size += state.nread;
1713
1714 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1715 state.nread / (1.024*this_time + 1.0e-4),
1716 put_total_size / (1.024*put_total_time_ms)));
1717 }
1718
1719 if (f == x_stdin) {
1720 cli_shutdown(cli);
1721 exit(0);
1722 }
1723
1724 return rc;
1725}
1726
1727/****************************************************************************
1728 Put a file.
1729****************************************************************************/
1730
1731static int cmd_put(void)
1732{
1733 TALLOC_CTX *ctx = talloc_tos();
1734 char *lname;
1735 char *rname;
1736 char *buf;
1737
1738 rname = talloc_strdup(ctx, client_get_cur_dir());
1739 if (!rname) {
1740 return 1;
1741 }
1742
1743 if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1744 d_printf("put <filename>\n");
1745 return 1;
1746 }
1747
1748 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1749 rname = talloc_asprintf_append(rname, "%s", buf);
1750 } else {
1751 rname = talloc_asprintf_append(rname, "%s", lname);
1752 }
1753 if (!rname) {
1754 return 1;
1755 }
1756
1757 rname = clean_name(ctx, rname);
1758 if (!rname) {
1759 return 1;
1760 }
1761
1762 {
1763 SMB_STRUCT_STAT st;
1764 /* allow '-' to represent stdin
1765 jdblair, 24.jun.98 */
1766 if (!file_exist_stat(lname,&st) &&
1767 (strcmp(lname,"-"))) {
1768 d_printf("%s does not exist\n",lname);
1769 return 1;
1770 }
1771 }
1772
1773 return do_put(rname, lname, false);
1774}
1775
1776/*************************************
1777 File list structure.
1778*************************************/
1779
1780static struct file_list {
1781 struct file_list *prev, *next;
1782 char *file_path;
1783 bool isdir;
1784} *file_list;
1785
1786/****************************************************************************
1787 Free a file_list structure.
1788****************************************************************************/
1789
1790static void free_file_list (struct file_list *l_head)
1791{
1792 struct file_list *list, *next;
1793
1794 for (list = l_head; list; list = next) {
1795 next = list->next;
1796 DLIST_REMOVE(l_head, list);
1797 SAFE_FREE(list->file_path);
1798 SAFE_FREE(list);
1799 }
1800}
1801
1802/****************************************************************************
1803 Seek in a directory/file list until you get something that doesn't start with
1804 the specified name.
1805****************************************************************************/
1806
1807static bool seek_list(struct file_list *list, char *name)
1808{
1809 while (list) {
1810 trim_string(list->file_path,"./","\n");
1811 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1812 return true;
1813 }
1814 list = list->next;
1815 }
1816
1817 return false;
1818}
1819
1820/****************************************************************************
1821 Set the file selection mask.
1822****************************************************************************/
1823
1824static int cmd_select(void)
1825{
1826 TALLOC_CTX *ctx = talloc_tos();
1827 char *new_fs = NULL;
1828 next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
1829 ;
1830 if (new_fs) {
1831 client_set_fileselection(new_fs);
1832 } else {
1833 client_set_fileselection("");
1834 }
1835 return 0;
1836}
1837
1838/****************************************************************************
1839 Recursive file matching function act as find
1840 match must be always set to true when calling this function
1841****************************************************************************/
1842
1843static int file_find(struct file_list **list, const char *directory,
1844 const char *expression, bool match)
1845{
1846 SMB_STRUCT_DIR *dir;
1847 struct file_list *entry;
1848 struct stat statbuf;
1849 int ret;
1850 char *path;
1851 bool isdir;
1852 const char *dname;
1853
1854 dir = sys_opendir(directory);
1855 if (!dir)
1856 return -1;
1857
1858 while ((dname = readdirname(dir))) {
1859 if (!strcmp("..", dname))
1860 continue;
1861 if (!strcmp(".", dname))
1862 continue;
1863
1864 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1865 continue;
1866 }
1867
1868 isdir = false;
1869 if (!match || !gen_fnmatch(expression, dname)) {
1870 if (recurse) {
1871 ret = stat(path, &statbuf);
1872 if (ret == 0) {
1873 if (S_ISDIR(statbuf.st_mode)) {
1874 isdir = true;
1875 ret = file_find(list, path, expression, false);
1876 }
1877 } else {
1878 d_printf("file_find: cannot stat file %s\n", path);
1879 }
1880
1881 if (ret == -1) {
1882 SAFE_FREE(path);
1883 sys_closedir(dir);
1884 return -1;
1885 }
1886 }
1887 entry = SMB_MALLOC_P(struct file_list);
1888 if (!entry) {
1889 d_printf("Out of memory in file_find\n");
1890 sys_closedir(dir);
1891 return -1;
1892 }
1893 entry->file_path = path;
1894 entry->isdir = isdir;
1895 DLIST_ADD(*list, entry);
1896 } else {
1897 SAFE_FREE(path);
1898 }
1899 }
1900
1901 sys_closedir(dir);
1902 return 0;
1903}
1904
1905/****************************************************************************
1906 mput some files.
1907****************************************************************************/
1908
1909static int cmd_mput(void)
1910{
1911 TALLOC_CTX *ctx = talloc_tos();
1912 char *p = NULL;
1913
1914 while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
1915 int ret;
1916 struct file_list *temp_list;
1917 char *quest, *lname, *rname;
1918
1919 file_list = NULL;
1920
1921 ret = file_find(&file_list, ".", p, true);
1922 if (ret) {
1923 free_file_list(file_list);
1924 continue;
1925 }
1926
1927 quest = NULL;
1928 lname = NULL;
1929 rname = NULL;
1930
1931 for (temp_list = file_list; temp_list;
1932 temp_list = temp_list->next) {
1933
1934 SAFE_FREE(lname);
1935 if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
1936 continue;
1937 }
1938 trim_string(lname, "./", "/");
1939
1940 /* check if it's a directory */
1941 if (temp_list->isdir) {
1942 /* if (!recurse) continue; */
1943
1944 SAFE_FREE(quest);
1945 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
1946 break;
1947 }
1948 if (prompt && !yesno(quest)) { /* No */
1949 /* Skip the directory */
1950 lname[strlen(lname)-1] = '/';
1951 if (!seek_list(temp_list, lname))
1952 break;
1953 } else { /* Yes */
1954 SAFE_FREE(rname);
1955 if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
1956 break;
1957 }
1958 normalize_name(rname);
1959 if (!cli_chkpath(cli, rname) &&
1960 !do_mkdir(rname)) {
1961 DEBUG (0, ("Unable to make dir, skipping..."));
1962 /* Skip the directory */
1963 lname[strlen(lname)-1] = '/';
1964 if (!seek_list(temp_list, lname)) {
1965 break;
1966 }
1967 }
1968 }
1969 continue;
1970 } else {
1971 SAFE_FREE(quest);
1972 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
1973 break;
1974 }
1975 if (prompt && !yesno(quest)) {
1976 /* No */
1977 continue;
1978 }
1979
1980 /* Yes */
1981 SAFE_FREE(rname);
1982 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
1983 break;
1984 }
1985 }
1986
1987 normalize_name(rname);
1988
1989 do_put(rname, lname, false);
1990 }
1991 free_file_list(file_list);
1992 SAFE_FREE(quest);
1993 SAFE_FREE(lname);
1994 SAFE_FREE(rname);
1995 }
1996
1997 return 0;
1998}
1999
2000/****************************************************************************
2001 Cancel a print job.
2002****************************************************************************/
2003
2004static int do_cancel(int job)
2005{
2006 if (cli_printjob_del(cli, job)) {
2007 d_printf("Job %d cancelled\n",job);
2008 return 0;
2009 } else {
2010 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
2011 return 1;
2012 }
2013}
2014
2015/****************************************************************************
2016 Cancel a print job.
2017****************************************************************************/
2018
2019static int cmd_cancel(void)
2020{
2021 TALLOC_CTX *ctx = talloc_tos();
2022 char *buf = NULL;
2023 int job;
2024
2025 if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2026 d_printf("cancel <jobid> ...\n");
2027 return 1;
2028 }
2029 do {
2030 job = atoi(buf);
2031 do_cancel(job);
2032 } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2033
2034 return 0;
2035}
2036
2037/****************************************************************************
2038 Print a file.
2039****************************************************************************/
2040
2041static int cmd_print(void)
2042{
2043 TALLOC_CTX *ctx = talloc_tos();
2044 char *lname = NULL;
2045 char *rname = NULL;
2046 char *p = NULL;
2047
2048 if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2049 d_printf("print <filename>\n");
2050 return 1;
2051 }
2052
2053 rname = talloc_strdup(ctx, lname);
2054 if (!rname) {
2055 return 1;
2056 }
2057 p = strrchr_m(rname,'/');
2058 if (p) {
2059 rname = talloc_asprintf(ctx,
2060 "%s-%d",
2061 p+1,
2062 (int)sys_getpid());
2063 }
2064 if (strequal(lname,"-")) {
2065 rname = talloc_asprintf(ctx,
2066 "stdin-%d",
2067 (int)sys_getpid());
2068 }
2069 if (!rname) {
2070 return 1;
2071 }
2072
2073 return do_put(rname, lname, false);
2074}
2075
2076/****************************************************************************
2077 Show a print queue entry.
2078****************************************************************************/
2079
2080static void queue_fn(struct print_job_info *p)
2081{
2082 d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
2083}
2084
2085/****************************************************************************
2086 Show a print queue.
2087****************************************************************************/
2088
2089static int cmd_queue(void)
2090{
2091 cli_print_queue(cli, queue_fn);
2092 return 0;
2093}
2094
2095/****************************************************************************
2096 Delete some files.
2097****************************************************************************/
2098
2099static void do_del(file_info *finfo, const char *dir)
2100{
2101 TALLOC_CTX *ctx = talloc_tos();
2102 char *mask = NULL;
2103
2104 mask = talloc_asprintf(ctx,
2105 "%s%c%s",
2106 dir,
2107 CLI_DIRSEP_CHAR,
2108 finfo->name);
2109 if (!mask) {
2110 return;
2111 }
2112
2113 if (finfo->mode & aDIR) {
2114 TALLOC_FREE(mask);
2115 return;
2116 }
2117
2118 if (!cli_unlink(finfo->cli, mask)) {
2119 d_printf("%s deleting remote file %s\n",
2120 cli_errstr(finfo->cli),mask);
2121 }
2122 TALLOC_FREE(mask);
2123}
2124
2125/****************************************************************************
2126 Delete some files.
2127****************************************************************************/
2128
2129static int cmd_del(void)
2130{
2131 TALLOC_CTX *ctx = talloc_tos();
2132 char *mask = NULL;
2133 char *buf = NULL;
2134 uint16 attribute = aSYSTEM | aHIDDEN;
2135
2136 if (recurse) {
2137 attribute |= aDIR;
2138 }
2139
2140 mask = talloc_strdup(ctx, client_get_cur_dir());
2141 if (!mask) {
2142 return 1;
2143 }
2144 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2145 d_printf("del <filename>\n");
2146 return 1;
2147 }
2148 mask = talloc_asprintf_append(mask, "%s", buf);
2149 if (!mask) {
2150 return 1;
2151 }
2152
2153 do_list(mask,attribute,do_del,false,false);
2154 return 0;
2155}
2156
2157/****************************************************************************
2158 Wildcard delete some files.
2159****************************************************************************/
2160
2161static int cmd_wdel(void)
2162{
2163 TALLOC_CTX *ctx = talloc_tos();
2164 char *mask = NULL;
2165 char *buf = NULL;
2166 uint16 attribute;
2167 struct cli_state *targetcli;
2168 char *targetname = NULL;
2169
2170 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2171 d_printf("wdel 0x<attrib> <wcard>\n");
2172 return 1;
2173 }
2174
2175 attribute = (uint16)strtol(buf, (char **)NULL, 16);
2176
2177 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2178 d_printf("wdel 0x<attrib> <wcard>\n");
2179 return 1;
2180 }
2181
2182 mask = talloc_asprintf(ctx, "%s%s",
2183 client_get_cur_dir(),
2184 buf);
2185 if (!mask) {
2186 return 1;
2187 }
2188
2189 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2190 d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
2191 return 1;
2192 }
2193
2194 if (!cli_unlink_full(targetcli, targetname, attribute)) {
2195 d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
2196 }
2197 return 0;
2198}
2199
2200/****************************************************************************
2201****************************************************************************/
2202
2203static int cmd_open(void)
2204{
2205 TALLOC_CTX *ctx = talloc_tos();
2206 char *mask = NULL;
2207 char *buf = NULL;
2208 char *targetname = NULL;
2209 struct cli_state *targetcli;
2210 int fnum;
2211
2212 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2213 d_printf("open <filename>\n");
2214 return 1;
2215 }
2216 mask = talloc_asprintf(ctx,
2217 "%s%s",
2218 client_get_cur_dir(),
2219 buf);
2220 if (!mask) {
2221 return 1;
2222 }
2223
2224 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2225 d_printf("open %s: %s\n", mask, cli_errstr(cli));
2226 return 1;
2227 }
2228
2229 fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
2230 if (fnum == -1) {
2231 fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
2232 if (fnum != -1) {
2233 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2234 } else {
2235 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2236 }
2237 } else {
2238 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2239 }
2240 return 0;
2241}
2242
2243static int cmd_posix_encrypt(void)
2244{
2245 TALLOC_CTX *ctx = talloc_tos();
2246 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2247
2248 if (cli->use_kerberos) {
2249 status = cli_gss_smb_encryption_start(cli);
2250 } else {
2251 char *domain = NULL;
2252 char *user = NULL;
2253 char *password = NULL;
2254
2255 if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
2256 d_printf("posix_encrypt domain user password\n");
2257 return 1;
2258 }
2259
2260 if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
2261 d_printf("posix_encrypt domain user password\n");
2262 return 1;
2263 }
2264
2265 if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
2266 d_printf("posix_encrypt domain user password\n");
2267 return 1;
2268 }
2269
2270 status = cli_raw_ntlm_smb_encryption_start(cli,
2271 user,
2272 password,
2273 domain);
2274 }
2275
2276 if (!NT_STATUS_IS_OK(status)) {
2277 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2278 } else {
2279 d_printf("encryption on\n");
2280 smb_encrypt = true;
2281 }
2282
2283 return 0;
2284}
2285
2286/****************************************************************************
2287****************************************************************************/
2288
2289static int cmd_posix_open(void)
2290{
2291 TALLOC_CTX *ctx = talloc_tos();
2292 char *mask = NULL;
2293 char *buf = NULL;
2294 char *targetname = NULL;
2295 struct cli_state *targetcli;
2296 mode_t mode;
2297 int fnum;
2298
2299 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2300 d_printf("posix_open <filename> 0<mode>\n");
2301 return 1;
2302 }
2303 mask = talloc_asprintf(ctx,
2304 "%s%s",
2305 client_get_cur_dir(),
2306 buf);
2307 if (!mask) {
2308 return 1;
2309 }
2310
2311 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2312 d_printf("posix_open <filename> 0<mode>\n");
2313 return 1;
2314 }
2315 mode = (mode_t)strtol(buf, (char **)NULL, 8);
2316
2317 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2318 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
2319 return 1;
2320 }
2321
2322 fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
2323 if (fnum == -1) {
2324 fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
2325 if (fnum != -1) {
2326 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2327 } else {
2328 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2329 }
2330 } else {
2331 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2332 }
2333
2334 return 0;
2335}
2336
2337static int cmd_posix_mkdir(void)
2338{
2339 TALLOC_CTX *ctx = talloc_tos();
2340 char *mask = NULL;
2341 char *buf = NULL;
2342 char *targetname = NULL;
2343 struct cli_state *targetcli;
2344 mode_t mode;
2345 int fnum;
2346
2347 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2348 d_printf("posix_mkdir <filename> 0<mode>\n");
2349 return 1;
2350 }
2351 mask = talloc_asprintf(ctx,
2352 "%s%s",
2353 client_get_cur_dir(),
2354 buf);
2355 if (!mask) {
2356 return 1;
2357 }
2358
2359 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2360 d_printf("posix_mkdir <filename> 0<mode>\n");
2361 return 1;
2362 }
2363 mode = (mode_t)strtol(buf, (char **)NULL, 8);
2364
2365 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2366 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
2367 return 1;
2368 }
2369
2370 fnum = cli_posix_mkdir(targetcli, targetname, mode);
2371 if (fnum == -1) {
2372 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2373 } else {
2374 d_printf("posix_mkdir created directory %s\n", targetname);
2375 }
2376 return 0;
2377}
2378
2379static int cmd_posix_unlink(void)
2380{
2381 TALLOC_CTX *ctx = talloc_tos();
2382 char *mask = NULL;
2383 char *buf = NULL;
2384 char *targetname = NULL;
2385 struct cli_state *targetcli;
2386
2387 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2388 d_printf("posix_unlink <filename>\n");
2389 return 1;
2390 }
2391 mask = talloc_asprintf(ctx,
2392 "%s%s",
2393 client_get_cur_dir(),
2394 buf);
2395 if (!mask) {
2396 return 1;
2397 }
2398
2399 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2400 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
2401 return 1;
2402 }
2403
2404 if (!cli_posix_unlink(targetcli, targetname)) {
2405 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
2406 } else {
2407 d_printf("posix_unlink deleted file %s\n", targetname);
2408 }
2409
2410 return 0;
2411}
2412
2413static int cmd_posix_rmdir(void)
2414{
2415 TALLOC_CTX *ctx = talloc_tos();
2416 char *mask = NULL;
2417 char *buf = NULL;
2418 char *targetname = NULL;
2419 struct cli_state *targetcli;
2420
2421 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2422 d_printf("posix_rmdir <filename>\n");
2423 return 1;
2424 }
2425 mask = talloc_asprintf(ctx,
2426 "%s%s",
2427 client_get_cur_dir(),
2428 buf);
2429 if (!mask) {
2430 return 1;
2431 }
2432
2433 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2434 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
2435 return 1;
2436 }
2437
2438 if (!cli_posix_rmdir(targetcli, targetname)) {
2439 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
2440 } else {
2441 d_printf("posix_rmdir deleted directory %s\n", targetname);
2442 }
2443
2444 return 0;
2445}
2446
2447static int cmd_close(void)
2448{
2449 TALLOC_CTX *ctx = talloc_tos();
2450 char *buf = NULL;
2451 int fnum;
2452
2453 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2454 d_printf("close <fnum>\n");
2455 return 1;
2456 }
2457
2458 fnum = atoi(buf);
2459 /* We really should use the targetcli here.... */
2460 if (!cli_close(cli, fnum)) {
2461 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
2462 return 1;
2463 }
2464 return 0;
2465}
2466
2467static int cmd_posix(void)
2468{
2469 TALLOC_CTX *ctx = talloc_tos();
2470 uint16 major, minor;
2471 uint32 caplow, caphigh;
2472 char *caps;
2473
2474 if (!SERVER_HAS_UNIX_CIFS(cli)) {
2475 d_printf("Server doesn't support UNIX CIFS extensions.\n");
2476 return 1;
2477 }
2478
2479 if (!cli_unix_extensions_version(cli, &major, &minor, &caplow, &caphigh)) {
2480 d_printf("Can't get UNIX CIFS extensions version from server.\n");
2481 return 1;
2482 }
2483
2484 d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2485
2486 caps = talloc_strdup(ctx, "");
2487 if (!caps) {
2488 return 1;
2489 }
2490 if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2491 caps = talloc_asprintf_append(caps, "locks ");
2492 if (!caps) {
2493 return 1;
2494 }
2495 }
2496 if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2497 caps = talloc_asprintf_append(caps, "acls ");
2498 if (!caps) {
2499 return 1;
2500 }
2501 }
2502 if (caplow & CIFS_UNIX_XATTTR_CAP) {
2503 caps = talloc_asprintf_append(caps, "eas ");
2504 if (!caps) {
2505 return 1;
2506 }
2507 }
2508 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2509 caps = talloc_asprintf_append(caps, "pathnames ");
2510 if (!caps) {
2511 return 1;
2512 }
2513 }
2514 if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2515 caps = talloc_asprintf_append(caps, "posix_path_operations ");
2516 if (!caps) {
2517 return 1;
2518 }
2519 }
2520 if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
2521 caps = talloc_asprintf_append(caps, "large_read ");
2522 if (!caps) {
2523 return 1;
2524 }
2525 }
2526 if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
2527 caps = talloc_asprintf_append(caps, "large_write ");
2528 if (!caps) {
2529 return 1;
2530 }
2531 }
2532 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
2533 caps = talloc_asprintf_append(caps, "posix_encrypt ");
2534 if (!caps) {
2535 return 1;
2536 }
2537 }
2538 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
2539 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
2540 if (!caps) {
2541 return 1;
2542 }
2543 }
2544
2545 if (*caps && caps[strlen(caps)-1] == ' ') {
2546 caps[strlen(caps)-1] = '\0';
2547 }
2548
2549 d_printf("Server supports CIFS capabilities %s\n", caps);
2550
2551 if (!cli_set_unix_extensions_capabilities(cli, major, minor, caplow, caphigh)) {
2552 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n", cli_errstr(cli));
2553 return 1;
2554 }
2555
2556 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2557 CLI_DIRSEP_CHAR = '/';
2558 *CLI_DIRSEP_STR = '/';
2559 client_set_cur_dir(CLI_DIRSEP_STR);
2560 }
2561
2562 return 0;
2563}
2564
2565static int cmd_lock(void)
2566{
2567 TALLOC_CTX *ctx = talloc_tos();
2568 char *buf = NULL;
2569 uint64_t start, len;
2570 enum brl_type lock_type;
2571 int fnum;
2572
2573 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2574 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2575 return 1;
2576 }
2577 fnum = atoi(buf);
2578
2579 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2580 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2581 return 1;
2582 }
2583
2584 if (*buf == 'r' || *buf == 'R') {
2585 lock_type = READ_LOCK;
2586 } else if (*buf == 'w' || *buf == 'W') {
2587 lock_type = WRITE_LOCK;
2588 } else {
2589 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2590 return 1;
2591 }
2592
2593 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2594 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2595 return 1;
2596 }
2597
2598 start = (uint64_t)strtol(buf, (char **)NULL, 16);
2599
2600 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2601 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2602 return 1;
2603 }
2604
2605 len = (uint64_t)strtol(buf, (char **)NULL, 16);
2606
2607 if (!cli_posix_lock(cli, fnum, start, len, true, lock_type)) {
2608 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2609 }
2610
2611 return 0;
2612}
2613
2614static int cmd_unlock(void)
2615{
2616 TALLOC_CTX *ctx = talloc_tos();
2617 char *buf = NULL;
2618 uint64_t start, len;
2619 int fnum;
2620
2621 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2622 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2623 return 1;
2624 }
2625 fnum = atoi(buf);
2626
2627 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2628 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2629 return 1;
2630 }
2631
2632 start = (uint64_t)strtol(buf, (char **)NULL, 16);
2633
2634 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2635 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2636 return 1;
2637 }
2638
2639 len = (uint64_t)strtol(buf, (char **)NULL, 16);
2640
2641 if (!cli_posix_unlock(cli, fnum, start, len)) {
2642 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2643 }
2644
2645 return 0;
2646}
2647
2648
2649/****************************************************************************
2650 Remove a directory.
2651****************************************************************************/
2652
2653static int cmd_rmdir(void)
2654{
2655 TALLOC_CTX *ctx = talloc_tos();
2656 char *mask = NULL;
2657 char *buf = NULL;
2658 char *targetname = NULL;
2659 struct cli_state *targetcli;
2660
2661 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2662 d_printf("rmdir <dirname>\n");
2663 return 1;
2664 }
2665 mask = talloc_asprintf(ctx,
2666 "%s%s",
2667 client_get_cur_dir(),
2668 buf);
2669 if (!mask) {
2670 return 1;
2671 }
2672
2673 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2674 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2675 return 1;
2676 }
2677
2678 if (!cli_rmdir(targetcli, targetname)) {
2679 d_printf("%s removing remote directory file %s\n",
2680 cli_errstr(targetcli),mask);
2681 }
2682
2683 return 0;
2684}
2685
2686/****************************************************************************
2687 UNIX hardlink.
2688****************************************************************************/
2689
2690static int cmd_link(void)
2691{
2692 TALLOC_CTX *ctx = talloc_tos();
2693 char *oldname = NULL;
2694 char *newname = NULL;
2695 char *buf = NULL;
2696 char *buf2 = NULL;
2697 char *targetname = NULL;
2698 struct cli_state *targetcli;
2699
2700 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2701 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2702 d_printf("link <oldname> <newname>\n");
2703 return 1;
2704 }
2705 oldname = talloc_asprintf(ctx,
2706 "%s%s",
2707 client_get_cur_dir(),
2708 buf);
2709 if (!oldname) {
2710 return 1;
2711 }
2712 newname = talloc_asprintf(ctx,
2713 "%s%s",
2714 client_get_cur_dir(),
2715 buf2);
2716 if (!newname) {
2717 return 1;
2718 }
2719
2720 if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
2721 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2722 return 1;
2723 }
2724
2725 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2726 d_printf("Server doesn't support UNIX CIFS calls.\n");
2727 return 1;
2728 }
2729
2730 if (!cli_unix_hardlink(targetcli, targetname, newname)) {
2731 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2732 return 1;
2733 }
2734 return 0;
2735}
2736
2737/****************************************************************************
2738 UNIX symlink.
2739****************************************************************************/
2740
2741static int cmd_symlink(void)
2742{
2743 TALLOC_CTX *ctx = talloc_tos();
2744 char *oldname = NULL;
2745 char *newname = NULL;
2746 char *buf = NULL;
2747 char *buf2 = NULL;
2748 char *targetname = NULL;
2749 struct cli_state *targetcli;
2750
2751 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2752 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2753 d_printf("symlink <oldname> <newname>\n");
2754 return 1;
2755 }
2756 oldname = talloc_asprintf(ctx,
2757 "%s%s",
2758 client_get_cur_dir(),
2759 buf);
2760 if (!oldname) {
2761 return 1;
2762 }
2763 newname = talloc_asprintf(ctx,
2764 "%s%s",
2765 client_get_cur_dir(),
2766 buf2);
2767 if (!newname) {
2768 return 1;
2769 }
2770
2771 if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
2772 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2773 return 1;
2774 }
2775
2776 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2777 d_printf("Server doesn't support UNIX CIFS calls.\n");
2778 return 1;
2779 }
2780
2781 if (!cli_unix_symlink(targetcli, targetname, newname)) {
2782 d_printf("%s symlinking files (%s -> %s)\n",
2783 cli_errstr(targetcli), newname, targetname);
2784 return 1;
2785 }
2786
2787 return 0;
2788}
2789
2790/****************************************************************************
2791 UNIX chmod.
2792****************************************************************************/
2793
2794static int cmd_chmod(void)
2795{
2796 TALLOC_CTX *ctx = talloc_tos();
2797 char *src = NULL;
2798 char *buf = NULL;
2799 char *buf2 = NULL;
2800 char *targetname = NULL;
2801 struct cli_state *targetcli;
2802 mode_t mode;
2803
2804 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2805 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2806 d_printf("chmod mode file\n");
2807 return 1;
2808 }
2809 src = talloc_asprintf(ctx,
2810 "%s%s",
2811 client_get_cur_dir(),
2812 buf2);
2813 if (!src) {
2814 return 1;
2815 }
2816
2817 mode = (mode_t)strtol(buf, NULL, 8);
2818
2819 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
2820 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
2821 return 1;
2822 }
2823
2824 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2825 d_printf("Server doesn't support UNIX CIFS calls.\n");
2826 return 1;
2827 }
2828
2829 if (!cli_unix_chmod(targetcli, targetname, mode)) {
2830 d_printf("%s chmod file %s 0%o\n",
2831 cli_errstr(targetcli), src, (unsigned int)mode);
2832 return 1;
2833 }
2834
2835 return 0;
2836}
2837
2838static const char *filetype_to_str(mode_t mode)
2839{
2840 if (S_ISREG(mode)) {
2841 return "regular file";
2842 } else if (S_ISDIR(mode)) {
2843 return "directory";
2844 } else
2845#ifdef S_ISCHR
2846 if (S_ISCHR(mode)) {
2847 return "character device";
2848 } else
2849#endif
2850#ifdef S_ISBLK
2851 if (S_ISBLK(mode)) {
2852 return "block device";
2853 } else
2854#endif
2855#ifdef S_ISFIFO
2856 if (S_ISFIFO(mode)) {
2857 return "fifo";
2858 } else
2859#endif
2860#ifdef S_ISLNK
2861 if (S_ISLNK(mode)) {
2862 return "symbolic link";
2863 } else
2864#endif
2865#ifdef S_ISSOCK
2866 if (S_ISSOCK(mode)) {
2867 return "socket";
2868 } else
2869#endif
2870 return "";
2871}
2872
2873static char rwx_to_str(mode_t m, mode_t bt, char ret)
2874{
2875 if (m & bt) {
2876 return ret;
2877 } else {
2878 return '-';
2879 }
2880}
2881
2882static char *unix_mode_to_str(char *s, mode_t m)
2883{
2884 char *p = s;
2885 const char *str = filetype_to_str(m);
2886
2887 switch(str[0]) {
2888 case 'd':
2889 *p++ = 'd';
2890 break;
2891 case 'c':
2892 *p++ = 'c';
2893 break;
2894 case 'b':
2895 *p++ = 'b';
2896 break;
2897 case 'f':
2898 *p++ = 'p';
2899 break;
2900 case 's':
2901 *p++ = str[1] == 'y' ? 'l' : 's';
2902 break;
2903 case 'r':
2904 default:
2905 *p++ = '-';
2906 break;
2907 }
2908 *p++ = rwx_to_str(m, S_IRUSR, 'r');
2909 *p++ = rwx_to_str(m, S_IWUSR, 'w');
2910 *p++ = rwx_to_str(m, S_IXUSR, 'x');
2911 *p++ = rwx_to_str(m, S_IRGRP, 'r');
2912 *p++ = rwx_to_str(m, S_IWGRP, 'w');
2913 *p++ = rwx_to_str(m, S_IXGRP, 'x');
2914 *p++ = rwx_to_str(m, S_IROTH, 'r');
2915 *p++ = rwx_to_str(m, S_IWOTH, 'w');
2916 *p++ = rwx_to_str(m, S_IXOTH, 'x');
2917 *p++ = '\0';
2918 return s;
2919}
2920
2921/****************************************************************************
2922 Utility function for UNIX getfacl.
2923****************************************************************************/
2924
2925static char *perms_to_string(fstring permstr, unsigned char perms)
2926{
2927 fstrcpy(permstr, "---");
2928 if (perms & SMB_POSIX_ACL_READ) {
2929 permstr[0] = 'r';
2930 }
2931 if (perms & SMB_POSIX_ACL_WRITE) {
2932 permstr[1] = 'w';
2933 }
2934 if (perms & SMB_POSIX_ACL_EXECUTE) {
2935 permstr[2] = 'x';
2936 }
2937 return permstr;
2938}
2939
2940/****************************************************************************
2941 UNIX getfacl.
2942****************************************************************************/
2943
2944static int cmd_getfacl(void)
2945{
2946 TALLOC_CTX *ctx = talloc_tos();
2947 char *src = NULL;
2948 char *name = NULL;
2949 char *targetname = NULL;
2950 struct cli_state *targetcli;
2951 uint16 major, minor;
2952 uint32 caplow, caphigh;
2953 char *retbuf = NULL;
2954 size_t rb_size = 0;
2955 SMB_STRUCT_STAT sbuf;
2956 uint16 num_file_acls = 0;
2957 uint16 num_dir_acls = 0;
2958 uint16 i;
2959
2960 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
2961 d_printf("getfacl filename\n");
2962 return 1;
2963 }
2964 src = talloc_asprintf(ctx,
2965 "%s%s",
2966 client_get_cur_dir(),
2967 name);
2968 if (!src) {
2969 return 1;
2970 }
2971
2972 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
2973 d_printf("stat %s: %s\n", src, cli_errstr(cli));
2974 return 1;
2975 }
2976
2977 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2978 d_printf("Server doesn't support UNIX CIFS calls.\n");
2979 return 1;
2980 }
2981
2982 if (!cli_unix_extensions_version(targetcli, &major, &minor,
2983 &caplow, &caphigh)) {
2984 d_printf("Can't get UNIX CIFS version from server.\n");
2985 return 1;
2986 }
2987
2988 if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
2989 d_printf("This server supports UNIX extensions "
2990 "but doesn't support POSIX ACLs.\n");
2991 return 1;
2992 }
2993
2994 if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
2995 d_printf("%s getfacl doing a stat on file %s\n",
2996 cli_errstr(targetcli), src);
2997 return 1;
2998 }
2999
3000 if (!cli_unix_getfacl(targetcli, targetname, &rb_size, &retbuf)) {
3001 d_printf("%s getfacl file %s\n",
3002 cli_errstr(targetcli), src);
3003 return 1;
3004 }
3005
3006 /* ToDo : Print out the ACL values. */
3007 if (SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION || rb_size < 6) {
3008 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3009 src, (unsigned int)CVAL(retbuf,0) );
3010 SAFE_FREE(retbuf);
3011 return 1;
3012 }
3013
3014 num_file_acls = SVAL(retbuf,2);
3015 num_dir_acls = SVAL(retbuf,4);
3016 if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3017 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3018 src,
3019 (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3020 (unsigned int)rb_size);
3021
3022 SAFE_FREE(retbuf);
3023 return 1;
3024 }
3025
3026 d_printf("# file: %s\n", src);
3027 d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
3028
3029 if (num_file_acls == 0 && num_dir_acls == 0) {
3030 d_printf("No acls found.\n");
3031 }
3032
3033 for (i = 0; i < num_file_acls; i++) {
3034 uint32 uorg;
3035 fstring permstring;
3036 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3037 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3038
3039 switch(tagtype) {
3040 case SMB_POSIX_ACL_USER_OBJ:
3041 d_printf("user::");
3042 break;
3043 case SMB_POSIX_ACL_USER:
3044 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3045 d_printf("user:%u:", uorg);
3046 break;
3047 case SMB_POSIX_ACL_GROUP_OBJ:
3048 d_printf("group::");
3049 break;
3050 case SMB_POSIX_ACL_GROUP:
3051 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3052 d_printf("group:%u:", uorg);
3053 break;
3054 case SMB_POSIX_ACL_MASK:
3055 d_printf("mask::");
3056 break;
3057 case SMB_POSIX_ACL_OTHER:
3058 d_printf("other::");
3059 break;
3060 default:
3061 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3062 src, (unsigned int)tagtype );
3063 SAFE_FREE(retbuf);
3064 return 1;
3065 }
3066
3067 d_printf("%s\n", perms_to_string(permstring, perms));
3068 }
3069
3070 for (i = 0; i < num_dir_acls; i++) {
3071 uint32 uorg;
3072 fstring permstring;
3073 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3074 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3075
3076 switch(tagtype) {
3077 case SMB_POSIX_ACL_USER_OBJ:
3078 d_printf("default:user::");
3079 break;
3080 case SMB_POSIX_ACL_USER:
3081 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3082 d_printf("default:user:%u:", uorg);
3083 break;
3084 case SMB_POSIX_ACL_GROUP_OBJ:
3085 d_printf("default:group::");
3086 break;
3087 case SMB_POSIX_ACL_GROUP:
3088 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3089 d_printf("default:group:%u:", uorg);
3090 break;
3091 case SMB_POSIX_ACL_MASK:
3092 d_printf("default:mask::");
3093 break;
3094 case SMB_POSIX_ACL_OTHER:
3095 d_printf("default:other::");
3096 break;
3097 default:
3098 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3099 src, (unsigned int)tagtype );
3100 SAFE_FREE(retbuf);
3101 return 1;
3102 }
3103
3104 d_printf("%s\n", perms_to_string(permstring, perms));
3105 }
3106
3107 SAFE_FREE(retbuf);
3108 return 0;
3109}
3110
3111/****************************************************************************
3112 UNIX stat.
3113****************************************************************************/
3114
3115static int cmd_stat(void)
3116{
3117 TALLOC_CTX *ctx = talloc_tos();
3118 char *src = NULL;
3119 char *name = NULL;
3120 char *targetname = NULL;
3121 struct cli_state *targetcli;
3122 fstring mode_str;
3123 SMB_STRUCT_STAT sbuf;
3124 struct tm *lt;
3125
3126 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3127 d_printf("stat file\n");
3128 return 1;
3129 }
3130 src = talloc_asprintf(ctx,
3131 "%s%s",
3132 client_get_cur_dir(),
3133 name);
3134 if (!src) {
3135 return 1;
3136 }
3137
3138 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3139 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3140 return 1;
3141 }
3142
3143 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3144 d_printf("Server doesn't support UNIX CIFS calls.\n");
3145 return 1;
3146 }
3147
3148 if (!cli_unix_stat(targetcli, targetname, &sbuf)) {
3149 d_printf("%s stat file %s\n",
3150 cli_errstr(targetcli), src);
3151 return 1;
3152 }
3153
3154 /* Print out the stat values. */
3155 d_printf("File: %s\n", src);
3156 d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
3157 (double)sbuf.st_size,
3158 (unsigned int)sbuf.st_blocks,
3159 filetype_to_str(sbuf.st_mode));
3160
3161#if defined(S_ISCHR) && defined(S_ISBLK)
3162 if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
3163 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
3164 (double)sbuf.st_ino,
3165 (unsigned int)sbuf.st_nlink,
3166 unix_dev_major(sbuf.st_rdev),
3167 unix_dev_minor(sbuf.st_rdev));
3168 } else
3169#endif
3170 d_printf("Inode: %.0f\tLinks: %u\n",
3171 (double)sbuf.st_ino,
3172 (unsigned int)sbuf.st_nlink);
3173
3174 d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
3175 ((int)sbuf.st_mode & 0777),
3176 unix_mode_to_str(mode_str, sbuf.st_mode),
3177 (unsigned int)sbuf.st_uid,
3178 (unsigned int)sbuf.st_gid);
3179
3180 lt = localtime(&sbuf.st_atime);
3181 if (lt) {
3182 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3183 } else {
3184 fstrcpy(mode_str, "unknown");
3185 }
3186 d_printf("Access: %s\n", mode_str);
3187
3188 lt = localtime(&sbuf.st_mtime);
3189 if (lt) {
3190 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3191 } else {
3192 fstrcpy(mode_str, "unknown");
3193 }
3194 d_printf("Modify: %s\n", mode_str);
3195
3196 lt = localtime(&sbuf.st_ctime);
3197 if (lt) {
3198 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3199 } else {
3200 fstrcpy(mode_str, "unknown");
3201 }
3202 d_printf("Change: %s\n", mode_str);
3203
3204 return 0;
3205}
3206
3207
3208/****************************************************************************
3209 UNIX chown.
3210****************************************************************************/
3211
3212static int cmd_chown(void)
3213{
3214 TALLOC_CTX *ctx = talloc_tos();
3215 char *src = NULL;
3216 uid_t uid;
3217 gid_t gid;
3218 char *buf, *buf2, *buf3;
3219 struct cli_state *targetcli;
3220 char *targetname = NULL;
3221
3222 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3223 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
3224 !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
3225 d_printf("chown uid gid file\n");
3226 return 1;
3227 }
3228
3229 uid = (uid_t)atoi(buf);
3230 gid = (gid_t)atoi(buf2);
3231
3232 src = talloc_asprintf(ctx,
3233 "%s%s",
3234 client_get_cur_dir(),
3235 buf3);
3236 if (!src) {
3237 return 1;
3238 }
3239 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname) ) {
3240 d_printf("chown %s: %s\n", src, cli_errstr(cli));
3241 return 1;
3242 }
3243
3244 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3245 d_printf("Server doesn't support UNIX CIFS calls.\n");
3246 return 1;
3247 }
3248
3249 if (!cli_unix_chown(targetcli, targetname, uid, gid)) {
3250 d_printf("%s chown file %s uid=%d, gid=%d\n",
3251 cli_errstr(targetcli), src, (int)uid, (int)gid);
3252 return 1;
3253 }
3254
3255 return 0;
3256}
3257
3258/****************************************************************************
3259 Rename some file.
3260****************************************************************************/
3261
3262static int cmd_rename(void)
3263{
3264 TALLOC_CTX *ctx = talloc_tos();
3265 char *src, *dest;
3266 char *buf, *buf2;
3267 struct cli_state *targetcli;
3268 char *targetsrc;
3269 char *targetdest;
3270
3271 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3272 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3273 d_printf("rename <src> <dest>\n");
3274 return 1;
3275 }
3276
3277 src = talloc_asprintf(ctx,
3278 "%s%s",
3279 client_get_cur_dir(),
3280 buf);
3281 if (!src) {
3282 return 1;
3283 }
3284
3285 dest = talloc_asprintf(ctx,
3286 "%s%s",
3287 client_get_cur_dir(),
3288 buf2);
3289 if (!dest) {
3290 return 1;
3291 }
3292
3293 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetsrc)) {
3294 d_printf("rename %s: %s\n", src, cli_errstr(cli));
3295 return 1;
3296 }
3297
3298 if (!cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli, &targetdest)) {
3299 d_printf("rename %s: %s\n", dest, cli_errstr(cli));
3300 return 1;
3301 }
3302
3303 if (!cli_rename(targetcli, targetsrc, targetdest)) {
3304 d_printf("%s renaming files %s -> %s \n",
3305 cli_errstr(targetcli),
3306 targetsrc,
3307 targetdest);
3308 return 1;
3309 }
3310
3311 return 0;
3312}
3313
3314/****************************************************************************
3315 Print the volume name.
3316****************************************************************************/
3317
3318static int cmd_volume(void)
3319{
3320 fstring volname;
3321 uint32 serial_num;
3322 time_t create_date;
3323
3324 if (!cli_get_fs_volume_info(cli, volname, &serial_num, &create_date)) {
3325 d_printf("Errr %s getting volume info\n",cli_errstr(cli));
3326 return 1;
3327 }
3328
3329 d_printf("Volume: |%s| serial number 0x%x\n",
3330 volname, (unsigned int)serial_num);
3331 return 0;
3332}
3333
3334/****************************************************************************
3335 Hard link files using the NT call.
3336****************************************************************************/
3337
3338static int cmd_hardlink(void)
3339{
3340 TALLOC_CTX *ctx = talloc_tos();
3341 char *src, *dest;
3342 char *buf, *buf2;
3343 struct cli_state *targetcli;
3344 char *targetname;
3345
3346 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3347 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3348 d_printf("hardlink <src> <dest>\n");
3349 return 1;
3350 }
3351
3352 src = talloc_asprintf(ctx,
3353 "%s%s",
3354 client_get_cur_dir(),
3355 buf);
3356 if (!src) {
3357 return 1;
3358 }
3359
3360 dest = talloc_asprintf(ctx,
3361 "%s%s",
3362 client_get_cur_dir(),
3363 buf2);
3364 if (!dest) {
3365 return 1;
3366 }
3367
3368 if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3369 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
3370 return 1;
3371 }
3372
3373 if (!cli_nt_hardlink(targetcli, targetname, dest)) {
3374 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
3375 return 1;
3376 }
3377
3378 return 0;
3379}
3380
3381/****************************************************************************
3382 Toggle the prompt flag.
3383****************************************************************************/
3384
3385static int cmd_prompt(void)
3386{
3387 prompt = !prompt;
3388 DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
3389 return 1;
3390}
3391
3392/****************************************************************************
3393 Set the newer than time.
3394****************************************************************************/
3395
3396static int cmd_newer(void)
3397{
3398 TALLOC_CTX *ctx = talloc_tos();
3399 char *buf;
3400 bool ok;
3401 SMB_STRUCT_STAT sbuf;
3402
3403 ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
3404 if (ok && (sys_stat(buf,&sbuf) == 0)) {
3405 newer_than = sbuf.st_mtime;
3406 DEBUG(1,("Getting files newer than %s",
3407 time_to_asc(newer_than)));
3408 } else {
3409 newer_than = 0;
3410 }
3411
3412 if (ok && newer_than == 0) {
3413 d_printf("Error setting newer-than time\n");
3414 return 1;
3415 }
3416
3417 return 0;
3418}
3419
3420/****************************************************************************
3421 Set the archive level.
3422****************************************************************************/
3423
3424static int cmd_archive(void)
3425{
3426 TALLOC_CTX *ctx = talloc_tos();
3427 char *buf;
3428
3429 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3430 archive_level = atoi(buf);
3431 } else {
3432 d_printf("Archive level is %d\n",archive_level);
3433 }
3434
3435 return 0;
3436}
3437
3438/****************************************************************************
3439 Toggle the lowercaseflag.
3440****************************************************************************/
3441
3442static int cmd_lowercase(void)
3443{
3444 lowercase = !lowercase;
3445 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
3446 return 0;
3447}
3448
3449/****************************************************************************
3450 Toggle the case sensitive flag.
3451****************************************************************************/
3452
3453static int cmd_setcase(void)
3454{
3455 bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
3456
3457 cli_set_case_sensitive(cli, !orig_case_sensitive);
3458 DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
3459 "on":"off"));
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: