/src/samba/source3/smbd/smb1_lanman.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | Inter-process communication and named pipe handling |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | Copyright (C) Jeremy Allison 2007. |
6 | | |
7 | | SMB Version handling |
8 | | Copyright (C) John H Terpstra 1995-1998 |
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 | | This file handles the named pipe and mailslot calls |
25 | | in the SMBtrans protocol |
26 | | */ |
27 | | |
28 | | #include "includes.h" |
29 | | #include "lib/util/util_file.h" |
30 | | #include "smbd/smbd.h" |
31 | | #include "smbd/globals.h" |
32 | | #include "source3/smbd/smbXsrv_session.h" |
33 | | #include "rpc_client/rpc_client.h" |
34 | | #include "../librpc/gen_ndr/ndr_samr_c.h" |
35 | | #include "../librpc/gen_ndr/ndr_spoolss_c.h" |
36 | | #include "rpc_client/cli_spoolss.h" |
37 | | #include "rpc_client/init_spoolss.h" |
38 | | #include "../librpc/gen_ndr/ndr_srvsvc_c.h" |
39 | | #include "../librpc/gen_ndr/rap.h" |
40 | | #include "../lib/util/binsearch.h" |
41 | | #include "../libcli/auth/libcli_auth.h" |
42 | | #include "rpc_client/init_lsa.h" |
43 | | #include "../libcli/security/security.h" |
44 | | #include "printing.h" |
45 | | #include "passdb/machine_sid.h" |
46 | | #include "auth.h" |
47 | | #include "rpc_server/rpc_ncacn_np.h" |
48 | | #include "lib/util/string_wrappers.h" |
49 | | #include "source3/printing/rap_jobid.h" |
50 | | #include "source3/lib/substitute.h" |
51 | | |
52 | | #ifdef CHECK_TYPES |
53 | | #undef CHECK_TYPES |
54 | | #endif |
55 | | #define CHECK_TYPES 0 |
56 | | |
57 | 0 | #define NERR_Success 0 |
58 | 0 | #define NERR_badpass 86 |
59 | 0 | #define NERR_notsupported 50 |
60 | | |
61 | 0 | #define NERR_BASE (2100) |
62 | | #define NERR_BufTooSmall (NERR_BASE+23) |
63 | 0 | #define NERR_JobNotFound (NERR_BASE+51) |
64 | 0 | #define NERR_DestNotFound (NERR_BASE+52) |
65 | | |
66 | | #define ACCESS_READ 0x01 |
67 | | #define ACCESS_WRITE 0x02 |
68 | | #define ACCESS_CREATE 0x04 |
69 | | |
70 | 0 | #define SHPWLEN 8 /* share password length */ |
71 | | |
72 | | /* Limit size of ipc replies */ |
73 | | |
74 | | static char *smb_realloc_limit(void *ptr, size_t size) |
75 | 0 | { |
76 | 0 | char *val; |
77 | |
|
78 | 0 | size = MAX((size),4*1024); |
79 | 0 | val = (char *)SMB_REALLOC(ptr,size); |
80 | 0 | if (val) { |
81 | 0 | memset(val,'\0',size); |
82 | 0 | } |
83 | 0 | return val; |
84 | 0 | } |
85 | | |
86 | | static bool api_Unsupported(struct smbd_server_connection *sconn, |
87 | | connection_struct *conn, uint64_t vuid, |
88 | | char *param, int tpscnt, |
89 | | char *data, int tdscnt, |
90 | | int mdrcnt, int mprcnt, |
91 | | char **rdata, char **rparam, |
92 | | int *rdata_len, int *rparam_len); |
93 | | |
94 | | static bool api_TooSmall(struct smbd_server_connection *sconn, |
95 | | connection_struct *conn, uint64_t vuid, char *param, char *data, |
96 | | int mdrcnt, int mprcnt, |
97 | | char **rdata, char **rparam, |
98 | | int *rdata_len, int *rparam_len); |
99 | | |
100 | | |
101 | | static int CopyExpanded(connection_struct *conn, |
102 | | int snum, char **dst, char *src, int *p_space_remaining) |
103 | 0 | { |
104 | 0 | TALLOC_CTX *ctx = talloc_tos(); |
105 | 0 | const struct loadparm_substitution *lp_sub = |
106 | 0 | loadparm_s3_global_substitution(); |
107 | 0 | char *buf = NULL; |
108 | 0 | int l; |
109 | |
|
110 | 0 | if (!src || !dst || !p_space_remaining || !(*dst) || |
111 | 0 | *p_space_remaining <= 0) { |
112 | 0 | return 0; |
113 | 0 | } |
114 | | |
115 | 0 | buf = talloc_strdup(ctx, src); |
116 | 0 | if (!buf) { |
117 | 0 | *p_space_remaining = 0; |
118 | 0 | return 0; |
119 | 0 | } |
120 | 0 | buf = talloc_string_sub(ctx, buf,"%S", lp_servicename(ctx, lp_sub, snum)); |
121 | 0 | if (!buf) { |
122 | 0 | *p_space_remaining = 0; |
123 | 0 | return 0; |
124 | 0 | } |
125 | 0 | buf = talloc_sub_full(ctx, |
126 | 0 | lp_servicename(ctx, lp_sub, SNUM(conn)), |
127 | 0 | conn->session_info->unix_info->unix_name, |
128 | 0 | conn->connectpath, |
129 | 0 | conn->session_info->unix_token->gid, |
130 | 0 | conn->session_info->unix_info->sanitized_username, |
131 | 0 | conn->session_info->info->domain_name, |
132 | 0 | buf); |
133 | 0 | if (!buf) { |
134 | 0 | *p_space_remaining = 0; |
135 | 0 | return 0; |
136 | 0 | } |
137 | 0 | l = push_ascii(*dst,buf,*p_space_remaining, STR_TERMINATE); |
138 | 0 | if (l == 0) { |
139 | 0 | return 0; |
140 | 0 | } |
141 | 0 | (*dst) += l; |
142 | 0 | (*p_space_remaining) -= l; |
143 | 0 | return l; |
144 | 0 | } |
145 | | |
146 | | static int CopyAndAdvance(char **dst, char *src, int *n) |
147 | 0 | { |
148 | 0 | int l; |
149 | 0 | if (!src || !dst || !n || !(*dst)) { |
150 | 0 | return 0; |
151 | 0 | } |
152 | 0 | l = push_ascii(*dst,src,*n, STR_TERMINATE); |
153 | 0 | if (l == 0) { |
154 | 0 | return 0; |
155 | 0 | } |
156 | 0 | (*dst) += l; |
157 | 0 | (*n) -= l; |
158 | 0 | return l; |
159 | 0 | } |
160 | | |
161 | | static int StrlenExpanded(connection_struct *conn, int snum, char *s) |
162 | 0 | { |
163 | 0 | TALLOC_CTX *ctx = talloc_tos(); |
164 | 0 | const struct loadparm_substitution *lp_sub = |
165 | 0 | loadparm_s3_global_substitution(); |
166 | 0 | char *buf = NULL; |
167 | 0 | if (!s) { |
168 | 0 | return 0; |
169 | 0 | } |
170 | 0 | buf = talloc_strdup(ctx,s); |
171 | 0 | if (!buf) { |
172 | 0 | return 0; |
173 | 0 | } |
174 | 0 | buf = talloc_string_sub(ctx,buf,"%S",lp_servicename(ctx, lp_sub, snum)); |
175 | 0 | if (!buf) { |
176 | 0 | return 0; |
177 | 0 | } |
178 | 0 | buf = talloc_sub_full(ctx, |
179 | 0 | lp_servicename(ctx, lp_sub, SNUM(conn)), |
180 | 0 | conn->session_info->unix_info->unix_name, |
181 | 0 | conn->connectpath, |
182 | 0 | conn->session_info->unix_token->gid, |
183 | 0 | conn->session_info->unix_info->sanitized_username, |
184 | 0 | conn->session_info->info->domain_name, |
185 | 0 | buf); |
186 | 0 | if (!buf) { |
187 | 0 | return 0; |
188 | 0 | } |
189 | 0 | return strlen(buf) + 1; |
190 | 0 | } |
191 | | |
192 | | /**************************************************************** |
193 | | Return an SVAL at a pointer, or failval if beyond the end. |
194 | | ****************************************************************/ |
195 | | |
196 | | static int get_safe_SVAL( |
197 | | const char *buf_base, |
198 | | size_t buf_len, |
199 | | char *ptr, |
200 | | size_t off, |
201 | | int failval) |
202 | 0 | { |
203 | | /* |
204 | | * Note we use off+1 here, not off+2 as SVAL accesses ptr[0] |
205 | | * and ptr[1], NOT ptr[2]. |
206 | | */ |
207 | 0 | if (!is_offset_safe(buf_base, buf_len, ptr, off+1)) { |
208 | 0 | return failval; |
209 | 0 | } |
210 | 0 | return SVAL(ptr,off); |
211 | 0 | } |
212 | | |
213 | | /**************************************************************** |
214 | | Return an IVAL at a pointer, or failval if beyond the end. |
215 | | ****************************************************************/ |
216 | | |
217 | | static int get_safe_IVAL( |
218 | | const char *buf_base, |
219 | | size_t buf_len, |
220 | | char *ptr, |
221 | | size_t off, |
222 | | int failval) |
223 | 0 | { |
224 | | /* |
225 | | * Note we use off+3 here, not off+4 as IVAL accesses |
226 | | * ptr[0] ptr[1] ptr[2] ptr[3] NOT ptr[4]. |
227 | | */ |
228 | 0 | if (!is_offset_safe(buf_base, buf_len, ptr, off+3)) { |
229 | 0 | return failval; |
230 | 0 | } |
231 | 0 | return IVAL(ptr,off); |
232 | 0 | } |
233 | | |
234 | | /**************************************************************** |
235 | | Return a safe pointer into a buffer, or NULL. |
236 | | ****************************************************************/ |
237 | | |
238 | | static char *get_safe_ptr( |
239 | | const char *buf_base, |
240 | | size_t buf_len, |
241 | | char *ptr, |
242 | | size_t off) |
243 | 0 | { |
244 | 0 | return is_offset_safe(buf_base, buf_len, ptr, off) ? |
245 | 0 | ptr + off : NULL; |
246 | 0 | } |
247 | | |
248 | | /******************************************************************* |
249 | | Check a API string for validity when we only need to check the prefix. |
250 | | ******************************************************************/ |
251 | | |
252 | | static bool prefix_ok(const char *str, const char *prefix) |
253 | 0 | { |
254 | 0 | return(strncmp(str,prefix,strlen(prefix)) == 0); |
255 | 0 | } |
256 | | |
257 | | struct pack_desc { |
258 | | const char *format; /* formatstring for structure */ |
259 | | const char *subformat; /* subformat for structure */ |
260 | | char *base; /* baseaddress of buffer */ |
261 | | int buflen; /* remaining size for fixed part; on init: length of base */ |
262 | | int subcount; /* count of substructures */ |
263 | | char *structbuf; /* pointer into buffer for remaining fixed part */ |
264 | | int stringlen; /* remaining size for variable part */ |
265 | | char *stringbuf; /* pointer into buffer for remaining variable part */ |
266 | | int neededlen; /* total needed size */ |
267 | | int usedlen; /* total used size (usedlen <= neededlen and usedlen <= buflen) */ |
268 | | const char *curpos; /* current position; pointer into format or subformat */ |
269 | | int errcode; |
270 | | }; |
271 | | |
272 | | static int get_counter(const char **p) |
273 | 0 | { |
274 | 0 | int i, n; |
275 | 0 | if (!p || !(*p)) { |
276 | 0 | return 1; |
277 | 0 | } |
278 | 0 | if (!isdigit((int)**p)) { |
279 | 0 | return 1; |
280 | 0 | } |
281 | 0 | for (n = 0;;) { |
282 | 0 | i = **p; |
283 | 0 | if (isdigit(i)) { |
284 | 0 | n = 10 * n + (i - '0'); |
285 | 0 | } else { |
286 | 0 | return n; |
287 | 0 | } |
288 | 0 | (*p)++; |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | | static int getlen(const char *p) |
293 | 0 | { |
294 | 0 | int n = 0; |
295 | 0 | if (!p) { |
296 | 0 | return 0; |
297 | 0 | } |
298 | | |
299 | 0 | while (*p) { |
300 | 0 | switch( *p++ ) { |
301 | 0 | case 'W': /* word (2 byte) */ |
302 | 0 | n += 2; |
303 | 0 | break; |
304 | 0 | case 'K': /* status word? (2 byte) */ |
305 | 0 | n += 2; |
306 | 0 | break; |
307 | 0 | case 'N': /* count of substructures (word) at end */ |
308 | 0 | n += 2; |
309 | 0 | break; |
310 | 0 | case 'D': /* double word (4 byte) */ |
311 | 0 | case 'z': /* offset to zero terminated string (4 byte) */ |
312 | 0 | case 'l': /* offset to user data (4 byte) */ |
313 | 0 | n += 4; |
314 | 0 | break; |
315 | 0 | case 'b': /* offset to data (with counter) (4 byte) */ |
316 | 0 | n += 4; |
317 | 0 | get_counter(&p); |
318 | 0 | break; |
319 | 0 | case 'B': /* byte (with optional counter) */ |
320 | 0 | n += get_counter(&p); |
321 | 0 | break; |
322 | 0 | } |
323 | 0 | } |
324 | 0 | return n; |
325 | 0 | } |
326 | | |
327 | | static bool init_package(struct pack_desc *p, int count, int subcount) |
328 | 0 | { |
329 | 0 | int n = p->buflen; |
330 | 0 | int i; |
331 | |
|
332 | 0 | if (!p->format || !p->base) { |
333 | 0 | return False; |
334 | 0 | } |
335 | | |
336 | 0 | i = count * getlen(p->format); |
337 | 0 | if (p->subformat) { |
338 | 0 | i += subcount * getlen(p->subformat); |
339 | 0 | } |
340 | 0 | p->structbuf = p->base; |
341 | 0 | p->neededlen = 0; |
342 | 0 | p->usedlen = 0; |
343 | 0 | p->subcount = 0; |
344 | 0 | p->curpos = p->format; |
345 | 0 | if (i > n) { |
346 | 0 | p->neededlen = i; |
347 | 0 | i = n = 0; |
348 | | #if 0 |
349 | | /* |
350 | | * This is the old error code we used. Apparently |
351 | | * WinNT/2k systems return ERRbuftoosmall (2123) and |
352 | | * OS/2 needs this. I'm leaving this here so we can revert |
353 | | * if needed. JRA. |
354 | | */ |
355 | | p->errcode = ERRmoredata; |
356 | | #else |
357 | 0 | p->errcode = ERRbuftoosmall; |
358 | 0 | #endif |
359 | 0 | } else { |
360 | 0 | p->errcode = NERR_Success; |
361 | 0 | } |
362 | 0 | p->buflen = i; |
363 | 0 | n -= i; |
364 | 0 | p->stringbuf = p->base + i; |
365 | 0 | p->stringlen = n; |
366 | 0 | return (p->errcode == NERR_Success); |
367 | 0 | } |
368 | | |
369 | | static int package(struct pack_desc *p, ...) |
370 | 0 | { |
371 | 0 | va_list args; |
372 | 0 | int needed=0, stringneeded; |
373 | 0 | const char *str=NULL; |
374 | 0 | int is_string=0, stringused; |
375 | 0 | int32_t temp; |
376 | |
|
377 | 0 | va_start(args,p); |
378 | |
|
379 | 0 | if (!*p->curpos) { |
380 | 0 | if (!p->subcount) { |
381 | 0 | p->curpos = p->format; |
382 | 0 | } else { |
383 | 0 | p->curpos = p->subformat; |
384 | 0 | p->subcount--; |
385 | 0 | } |
386 | 0 | } |
387 | | #if CHECK_TYPES |
388 | | str = va_arg(args,char*); |
389 | | SMB_ASSERT(strncmp(str,p->curpos,strlen(str)) == 0); |
390 | | #endif |
391 | 0 | stringneeded = -1; |
392 | |
|
393 | 0 | if (!p->curpos) { |
394 | 0 | va_end(args); |
395 | 0 | return 0; |
396 | 0 | } |
397 | | |
398 | 0 | switch( *p->curpos++ ) { |
399 | 0 | case 'W': /* word (2 byte) */ |
400 | 0 | needed = 2; |
401 | 0 | temp = va_arg(args,int); |
402 | 0 | if (p->buflen >= needed) { |
403 | 0 | SSVAL(p->structbuf,0,temp); |
404 | 0 | } |
405 | 0 | break; |
406 | 0 | case 'K': /* status word? (2 byte) */ |
407 | 0 | needed = 2; |
408 | 0 | temp = va_arg(args,int); |
409 | 0 | if (p->buflen >= needed) { |
410 | 0 | SSVAL(p->structbuf,0,temp); |
411 | 0 | } |
412 | 0 | break; |
413 | 0 | case 'N': /* count of substructures (word) at end */ |
414 | 0 | needed = 2; |
415 | 0 | p->subcount = va_arg(args,int); |
416 | 0 | if (p->buflen >= needed) { |
417 | 0 | SSVAL(p->structbuf,0,p->subcount); |
418 | 0 | } |
419 | 0 | break; |
420 | 0 | case 'D': /* double word (4 byte) */ |
421 | 0 | needed = 4; |
422 | 0 | temp = va_arg(args,int); |
423 | 0 | if (p->buflen >= needed) { |
424 | 0 | SIVAL(p->structbuf,0,temp); |
425 | 0 | } |
426 | 0 | break; |
427 | 0 | case 'B': /* byte (with optional counter) */ |
428 | 0 | needed = get_counter(&p->curpos); |
429 | 0 | { |
430 | 0 | char *s = va_arg(args,char*); |
431 | 0 | if (p->buflen >= needed) { |
432 | 0 | strlcpy(p->structbuf,s?s:"",needed); |
433 | 0 | } |
434 | 0 | } |
435 | 0 | break; |
436 | 0 | case 'z': /* offset to zero terminated string (4 byte) */ |
437 | 0 | str = va_arg(args,char*); |
438 | 0 | stringneeded = (str ? strlen(str)+1 : 0); |
439 | 0 | is_string = 1; |
440 | 0 | break; |
441 | 0 | case 'l': /* offset to user data (4 byte) */ |
442 | 0 | str = va_arg(args,char*); |
443 | 0 | stringneeded = va_arg(args,int); |
444 | 0 | is_string = 0; |
445 | 0 | break; |
446 | 0 | case 'b': /* offset to data (with counter) (4 byte) */ |
447 | 0 | str = va_arg(args,char*); |
448 | 0 | stringneeded = get_counter(&p->curpos); |
449 | 0 | is_string = 0; |
450 | 0 | break; |
451 | 0 | } |
452 | | |
453 | 0 | va_end(args); |
454 | 0 | if (stringneeded >= 0) { |
455 | 0 | needed = 4; |
456 | 0 | if (p->buflen >= needed) { |
457 | 0 | stringused = stringneeded; |
458 | 0 | if (stringused > p->stringlen) { |
459 | 0 | stringused = (is_string ? p->stringlen : 0); |
460 | 0 | if (p->errcode == NERR_Success) { |
461 | 0 | p->errcode = ERRmoredata; |
462 | 0 | } |
463 | 0 | } |
464 | 0 | if (!stringused) { |
465 | 0 | SIVAL(p->structbuf,0,0); |
466 | 0 | } else { |
467 | 0 | SIVAL(p->structbuf,0,PTR_DIFF(p->stringbuf,p->base)); |
468 | 0 | memcpy(p->stringbuf,str?str:"",stringused); |
469 | 0 | if (is_string) { |
470 | 0 | p->stringbuf[stringused-1] = '\0'; |
471 | 0 | } |
472 | 0 | p->stringbuf += stringused; |
473 | 0 | p->stringlen -= stringused; |
474 | 0 | p->usedlen += stringused; |
475 | 0 | } |
476 | 0 | } |
477 | 0 | p->neededlen += stringneeded; |
478 | 0 | } |
479 | |
|
480 | 0 | p->neededlen += needed; |
481 | 0 | if (p->buflen >= needed) { |
482 | 0 | p->structbuf += needed; |
483 | 0 | p->buflen -= needed; |
484 | 0 | p->usedlen += needed; |
485 | 0 | } else { |
486 | 0 | if (p->errcode == NERR_Success) { |
487 | 0 | p->errcode = ERRmoredata; |
488 | 0 | } |
489 | 0 | } |
490 | 0 | return 1; |
491 | 0 | } |
492 | | |
493 | | #if CHECK_TYPES |
494 | | #define PACK(desc,t,v) package(desc,t,v,0,0,0,0) |
495 | | #define PACKl(desc,t,v,l) package(desc,t,v,l,0,0,0,0) |
496 | | #else |
497 | 0 | #define PACK(desc,t,v) package(desc,v) |
498 | 0 | #define PACKl(desc,t,v,l) package(desc,v,l) |
499 | | #endif |
500 | | |
501 | | static void PACKI(struct pack_desc* desc, const char *t,int v) |
502 | 0 | { |
503 | 0 | PACK(desc,t,v); |
504 | 0 | } |
505 | | |
506 | | static void PACKS(struct pack_desc* desc,const char *t,const char *v) |
507 | 0 | { |
508 | 0 | PACK(desc,t,v); |
509 | 0 | } |
510 | | |
511 | | /**************************************************************************** |
512 | | Get a print queue. |
513 | | ****************************************************************************/ |
514 | | |
515 | | static void PackDriverData(struct pack_desc* desc) |
516 | 0 | { |
517 | 0 | char drivdata[4+4+32]; |
518 | 0 | SIVAL(drivdata,0,sizeof drivdata); /* cb */ |
519 | 0 | SIVAL(drivdata,4,1000); /* lVersion */ |
520 | 0 | memset(drivdata+8,0,32); /* szDeviceName */ |
521 | 0 | push_ascii(drivdata+8,"NULL",32, STR_TERMINATE); |
522 | 0 | PACKl(desc,"l",drivdata,sizeof drivdata); /* pDriverData */ |
523 | 0 | } |
524 | | |
525 | | static int check_printq_info(struct pack_desc* desc, |
526 | | unsigned int uLevel, char *id1, char *id2) |
527 | 0 | { |
528 | 0 | desc->subformat = NULL; |
529 | 0 | switch( uLevel ) { |
530 | 0 | case 0: |
531 | 0 | desc->format = "B13"; |
532 | 0 | break; |
533 | 0 | case 1: |
534 | 0 | desc->format = "B13BWWWzzzzzWW"; |
535 | 0 | break; |
536 | 0 | case 2: |
537 | 0 | desc->format = "B13BWWWzzzzzWN"; |
538 | 0 | desc->subformat = "WB21BB16B10zWWzDDz"; |
539 | 0 | break; |
540 | 0 | case 3: |
541 | 0 | desc->format = "zWWWWzzzzWWzzl"; |
542 | 0 | break; |
543 | 0 | case 4: |
544 | 0 | desc->format = "zWWWWzzzzWNzzl"; |
545 | 0 | desc->subformat = "WWzWWDDzz"; |
546 | 0 | break; |
547 | 0 | case 5: |
548 | 0 | desc->format = "z"; |
549 | 0 | break; |
550 | 0 | case 51: |
551 | 0 | desc->format = "K"; |
552 | 0 | break; |
553 | 0 | case 52: |
554 | 0 | desc->format = "WzzzzzzzzN"; |
555 | 0 | desc->subformat = "z"; |
556 | 0 | break; |
557 | 0 | default: |
558 | 0 | DEBUG(0,("check_printq_info: invalid level %d\n", |
559 | 0 | uLevel )); |
560 | 0 | return False; |
561 | 0 | } |
562 | 0 | if (id1 == NULL || strcmp(desc->format,id1) != 0) { |
563 | 0 | DEBUG(0,("check_printq_info: invalid format %s\n", |
564 | 0 | id1 ? id1 : "<NULL>" )); |
565 | 0 | return False; |
566 | 0 | } |
567 | 0 | if (desc->subformat && (id2 == NULL || strcmp(desc->subformat,id2) != 0)) { |
568 | 0 | DEBUG(0,("check_printq_info: invalid subformat %s\n", |
569 | 0 | id2 ? id2 : "<NULL>" )); |
570 | 0 | return False; |
571 | 0 | } |
572 | 0 | return True; |
573 | 0 | } |
574 | | |
575 | | |
576 | 0 | #define RAP_JOB_STATUS_QUEUED 0 |
577 | 0 | #define RAP_JOB_STATUS_PAUSED 1 |
578 | 0 | #define RAP_JOB_STATUS_SPOOLING 2 |
579 | 0 | #define RAP_JOB_STATUS_PRINTING 3 |
580 | | #define RAP_JOB_STATUS_PRINTED 4 |
581 | | |
582 | 0 | #define RAP_QUEUE_STATUS_PAUSED 1 |
583 | 0 | #define RAP_QUEUE_STATUS_ERROR 2 |
584 | | |
585 | | /* turn a print job status into a on the wire status |
586 | | */ |
587 | | static int printj_spoolss_status(int v) |
588 | 0 | { |
589 | 0 | if (v == JOB_STATUS_QUEUED) |
590 | 0 | return RAP_JOB_STATUS_QUEUED; |
591 | 0 | if (v & JOB_STATUS_PAUSED) |
592 | 0 | return RAP_JOB_STATUS_PAUSED; |
593 | 0 | if (v & JOB_STATUS_SPOOLING) |
594 | 0 | return RAP_JOB_STATUS_SPOOLING; |
595 | 0 | if (v & JOB_STATUS_PRINTING) |
596 | 0 | return RAP_JOB_STATUS_PRINTING; |
597 | 0 | return 0; |
598 | 0 | } |
599 | | |
600 | | /* turn a print queue status into a on the wire status |
601 | | */ |
602 | | static int printq_spoolss_status(int v) |
603 | 0 | { |
604 | 0 | if (v == PRINTER_STATUS_OK) |
605 | 0 | return 0; |
606 | 0 | if (v & PRINTER_STATUS_PAUSED) |
607 | 0 | return RAP_QUEUE_STATUS_PAUSED; |
608 | 0 | return RAP_QUEUE_STATUS_ERROR; |
609 | 0 | } |
610 | | |
611 | | static void fill_spoolss_printjob_info(int uLevel, |
612 | | struct pack_desc *desc, |
613 | | struct spoolss_JobInfo2 *info2, |
614 | | int n) |
615 | 0 | { |
616 | 0 | time_t t = spoolss_Time_to_time_t(&info2->submitted); |
617 | | |
618 | | /* the client expects localtime */ |
619 | 0 | t -= get_time_zone(t); |
620 | |
|
621 | 0 | PACKI(desc,"W",pjobid_to_rap(info2->printer_name, info2->job_id)); /* uJobId */ |
622 | 0 | if (uLevel == 1) { |
623 | 0 | PACKS(desc,"B21", info2->user_name); /* szUserName */ |
624 | 0 | PACKS(desc,"B",""); /* pad */ |
625 | 0 | PACKS(desc,"B16",""); /* szNotifyName */ |
626 | 0 | PACKS(desc,"B10","PM_Q_RAW"); /* szDataType */ |
627 | 0 | PACKS(desc,"z",""); /* pszParms */ |
628 | 0 | PACKI(desc,"W",n+1); /* uPosition */ |
629 | 0 | PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */ |
630 | 0 | PACKS(desc,"z",""); /* pszStatus */ |
631 | 0 | PACKI(desc,"D", t); /* ulSubmitted */ |
632 | 0 | PACKI(desc,"D", info2->size); /* ulSize */ |
633 | 0 | PACKS(desc,"z", info2->document_name); /* pszComment */ |
634 | 0 | } |
635 | 0 | if (uLevel == 2 || uLevel == 3 || uLevel == 4) { |
636 | 0 | PACKI(desc,"W", info2->priority); /* uPriority */ |
637 | 0 | PACKS(desc,"z", info2->user_name); /* pszUserName */ |
638 | 0 | PACKI(desc,"W",n+1); /* uPosition */ |
639 | 0 | PACKI(desc,"W", printj_spoolss_status(info2->status)); /* fsStatus */ |
640 | 0 | PACKI(desc,"D",t); /* ulSubmitted */ |
641 | 0 | PACKI(desc,"D", info2->size); /* ulSize */ |
642 | 0 | PACKS(desc,"z","Samba"); /* pszComment */ |
643 | 0 | PACKS(desc,"z", info2->document_name); /* pszDocument */ |
644 | 0 | if (uLevel == 3) { |
645 | 0 | PACKS(desc,"z",""); /* pszNotifyName */ |
646 | 0 | PACKS(desc,"z","PM_Q_RAW"); /* pszDataType */ |
647 | 0 | PACKS(desc,"z",""); /* pszParms */ |
648 | 0 | PACKS(desc,"z",""); /* pszStatus */ |
649 | 0 | PACKS(desc,"z", info2->printer_name); /* pszQueue */ |
650 | 0 | PACKS(desc,"z","lpd"); /* pszQProcName */ |
651 | 0 | PACKS(desc,"z",""); /* pszQProcParms */ |
652 | 0 | PACKS(desc,"z","NULL"); /* pszDriverName */ |
653 | 0 | PackDriverData(desc); /* pDriverData */ |
654 | 0 | PACKS(desc,"z",""); /* pszPrinterName */ |
655 | 0 | } else if (uLevel == 4) { /* OS2 */ |
656 | 0 | PACKS(desc,"z",""); /* pszSpoolFileName */ |
657 | 0 | PACKS(desc,"z",""); /* pszPortName */ |
658 | 0 | PACKS(desc,"z",""); /* pszStatus */ |
659 | 0 | PACKI(desc,"D",0); /* ulPagesSpooled */ |
660 | 0 | PACKI(desc,"D",0); /* ulPagesSent */ |
661 | 0 | PACKI(desc,"D",0); /* ulPagesPrinted */ |
662 | 0 | PACKI(desc,"D",0); /* ulTimePrinted */ |
663 | 0 | PACKI(desc,"D",0); /* ulExtendJobStatus */ |
664 | 0 | PACKI(desc,"D",0); /* ulStartPage */ |
665 | 0 | PACKI(desc,"D",0); /* ulEndPage */ |
666 | 0 | } |
667 | 0 | } |
668 | 0 | } |
669 | | |
670 | | /******************************************************************** |
671 | | Respond to the DosPrintQInfo command with a level of 52 |
672 | | This is used to get printer driver information for Win9x clients |
673 | | ********************************************************************/ |
674 | | static void fill_printq_info_52(struct spoolss_DriverInfo3 *driver, |
675 | | struct pack_desc* desc, int count, |
676 | | const char *printer_name) |
677 | 0 | { |
678 | 0 | int i; |
679 | 0 | fstring location; |
680 | 0 | trim_string(discard_const_p(char, driver->driver_path), "\\print$\\WIN40\\0\\", 0); |
681 | 0 | trim_string(discard_const_p(char, driver->data_file), "\\print$\\WIN40\\0\\", 0); |
682 | 0 | trim_string(discard_const_p(char, driver->help_file), "\\print$\\WIN40\\0\\", 0); |
683 | |
|
684 | 0 | PACKI(desc, "W", 0x0400); /* don't know */ |
685 | 0 | PACKS(desc, "z", driver->driver_name); /* long printer name */ |
686 | 0 | PACKS(desc, "z", driver->driver_path); /* Driverfile Name */ |
687 | 0 | PACKS(desc, "z", driver->data_file); /* Datafile name */ |
688 | 0 | PACKS(desc, "z", driver->monitor_name); /* language monitor */ |
689 | |
|
690 | 0 | fstrcpy(location, "\\\\%L\\print$\\WIN40\\0"); |
691 | 0 | standard_sub_basic( "", "", location, sizeof(location)-1 ); |
692 | 0 | PACKS(desc,"z", location); /* share to retrieve files */ |
693 | |
|
694 | 0 | PACKS(desc,"z", driver->default_datatype); /* default data type */ |
695 | 0 | PACKS(desc,"z", driver->help_file); /* helpfile name */ |
696 | 0 | PACKS(desc,"z", driver->driver_path); /* driver name */ |
697 | |
|
698 | 0 | DEBUG(3,("Printer Driver Name: %s:\n",driver->driver_name)); |
699 | 0 | DEBUG(3,("Driver: %s:\n",driver->driver_path)); |
700 | 0 | DEBUG(3,("Data File: %s:\n",driver->data_file)); |
701 | 0 | DEBUG(3,("Language Monitor: %s:\n",driver->monitor_name)); |
702 | 0 | DEBUG(3,("Driver Location: %s:\n",location)); |
703 | 0 | DEBUG(3,("Data Type: %s:\n",driver->default_datatype)); |
704 | 0 | DEBUG(3,("Help File: %s:\n",driver->help_file)); |
705 | 0 | PACKI(desc,"N",count); /* number of files to copy */ |
706 | |
|
707 | 0 | for ( i=0; i<count && driver->dependent_files && *driver->dependent_files[i]; i++) |
708 | 0 | { |
709 | 0 | trim_string(discard_const_p(char, driver->dependent_files[i]), "\\print$\\WIN40\\0\\", 0); |
710 | 0 | PACKS(desc,"z",driver->dependent_files[i]); /* driver files to copy */ |
711 | 0 | DEBUG(3,("Dependent File: %s:\n", driver->dependent_files[i])); |
712 | 0 | } |
713 | | |
714 | | /* sanity check */ |
715 | 0 | if ( i != count ) |
716 | 0 | DEBUG(3,("fill_printq_info_52: file count specified by client [%d] != number of dependent files [%i]\n", |
717 | 0 | count, i)); |
718 | |
|
719 | 0 | DEBUG(3,("fill_printq_info on <%s> gave %d entries\n", printer_name, i)); |
720 | |
|
721 | 0 | desc->errcode=NERR_Success; |
722 | |
|
723 | 0 | } |
724 | | |
725 | | static const char *strip_unc(const char *unc) |
726 | 0 | { |
727 | 0 | char *p; |
728 | |
|
729 | 0 | if (unc == NULL) { |
730 | 0 | return NULL; |
731 | 0 | } |
732 | | |
733 | 0 | if ((p = strrchr(unc, '\\')) != NULL) { |
734 | 0 | return p+1; |
735 | 0 | } |
736 | | |
737 | 0 | return unc; |
738 | 0 | } |
739 | | |
740 | | static void fill_printq_info(int uLevel, |
741 | | struct pack_desc* desc, |
742 | | int count, |
743 | | union spoolss_JobInfo *job_info, |
744 | | struct spoolss_DriverInfo3 *driver_info, |
745 | | struct spoolss_PrinterInfo2 *printer_info) |
746 | 0 | { |
747 | 0 | switch (uLevel) { |
748 | 0 | case 0: |
749 | 0 | case 1: |
750 | 0 | case 2: |
751 | 0 | PACKS(desc,"B13", strip_unc(printer_info->printername)); |
752 | 0 | break; |
753 | 0 | case 3: |
754 | 0 | case 4: |
755 | 0 | case 5: |
756 | 0 | PACKS(desc,"z", strip_unc(printer_info->printername)); |
757 | 0 | break; |
758 | 0 | case 51: |
759 | 0 | PACKI(desc,"K", printq_spoolss_status(printer_info->status)); |
760 | 0 | break; |
761 | 0 | } |
762 | | |
763 | 0 | if (uLevel == 1 || uLevel == 2) { |
764 | 0 | PACKS(desc,"B",""); /* alignment */ |
765 | 0 | PACKI(desc,"W",5); /* priority */ |
766 | 0 | PACKI(desc,"W",0); /* start time */ |
767 | 0 | PACKI(desc,"W",0); /* until time */ |
768 | 0 | PACKS(desc,"z",""); /* pSepFile */ |
769 | 0 | PACKS(desc,"z","lpd"); /* pPrProc */ |
770 | 0 | PACKS(desc,"z", strip_unc(printer_info->printername)); /* pDestinations */ |
771 | 0 | PACKS(desc,"z",""); /* pParms */ |
772 | 0 | if (printer_info->printername == NULL) { |
773 | 0 | PACKS(desc,"z","UNKNOWN PRINTER"); |
774 | 0 | PACKI(desc,"W",LPSTAT_ERROR); |
775 | 0 | } else { |
776 | 0 | PACKS(desc,"z", printer_info->comment); |
777 | 0 | PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* status */ |
778 | 0 | } |
779 | 0 | PACKI(desc,(uLevel == 1 ? "W" : "N"),count); |
780 | 0 | } |
781 | |
|
782 | 0 | if (uLevel == 3 || uLevel == 4) { |
783 | 0 | PACKI(desc,"W",5); /* uPriority */ |
784 | 0 | PACKI(desc,"W",0); /* uStarttime */ |
785 | 0 | PACKI(desc,"W",0); /* uUntiltime */ |
786 | 0 | PACKI(desc,"W",5); /* pad1 */ |
787 | 0 | PACKS(desc,"z",""); /* pszSepFile */ |
788 | 0 | PACKS(desc,"z","WinPrint"); /* pszPrProc */ |
789 | 0 | PACKS(desc,"z",NULL); /* pszParms */ |
790 | 0 | PACKS(desc,"z",NULL); /* pszComment - don't ask.... JRA */ |
791 | | /* "don't ask" that it's done this way to fix corrupted |
792 | | Win9X/ME printer comments. */ |
793 | 0 | PACKI(desc,"W", printq_spoolss_status(printer_info->status)); /* fsStatus */ |
794 | 0 | PACKI(desc,(uLevel == 3 ? "W" : "N"),count); /* cJobs */ |
795 | 0 | PACKS(desc,"z", strip_unc(printer_info->printername)); /* pszPrinters */ |
796 | 0 | PACKS(desc,"z", printer_info->drivername); /* pszDriverName */ |
797 | 0 | PackDriverData(desc); /* pDriverData */ |
798 | 0 | } |
799 | |
|
800 | 0 | if (uLevel == 2 || uLevel == 4) { |
801 | 0 | int i; |
802 | 0 | for (i = 0; i < count; i++) { |
803 | 0 | fill_spoolss_printjob_info(uLevel == 2 ? 1 : 2, desc, &job_info[i].info2, i); |
804 | 0 | } |
805 | 0 | } |
806 | |
|
807 | 0 | if (uLevel==52) |
808 | 0 | fill_printq_info_52(driver_info, desc, count, printer_info->printername); |
809 | 0 | } |
810 | | |
811 | | /* This function returns the number of files for a given driver */ |
812 | | static int get_printerdrivernumber(const struct spoolss_DriverInfo3 *driver) |
813 | 0 | { |
814 | 0 | int result = 0; |
815 | | |
816 | | /* count the number of files */ |
817 | 0 | while (driver->dependent_files && *driver->dependent_files[result]) |
818 | 0 | result++; |
819 | |
|
820 | 0 | return result; |
821 | 0 | } |
822 | | |
823 | | static bool api_DosPrintQGetInfo(struct smbd_server_connection *sconn, |
824 | | connection_struct *conn, uint64_t vuid, |
825 | | char *param, int tpscnt, |
826 | | char *data, int tdscnt, |
827 | | int mdrcnt,int mprcnt, |
828 | | char **rdata,char **rparam, |
829 | | int *rdata_len,int *rparam_len) |
830 | 0 | { |
831 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
832 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
833 | 0 | char *p = skip_string(param,tpscnt,str2); |
834 | 0 | char *QueueName = p; |
835 | 0 | unsigned int uLevel; |
836 | 0 | uint32_t count = 0; |
837 | 0 | char *str3; |
838 | 0 | struct pack_desc desc; |
839 | 0 | char* tmpdata=NULL; |
840 | |
|
841 | 0 | WERROR werr = WERR_OK; |
842 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
843 | 0 | NTSTATUS status; |
844 | 0 | struct rpc_pipe_client *cli = NULL; |
845 | 0 | struct dcerpc_binding_handle *b = NULL; |
846 | 0 | struct policy_handle handle; |
847 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
848 | 0 | union spoolss_DriverInfo driver_info; |
849 | 0 | union spoolss_JobInfo *job_info = NULL; |
850 | 0 | union spoolss_PrinterInfo printer_info; |
851 | |
|
852 | 0 | if (!str1 || !str2 || !p) { |
853 | 0 | return False; |
854 | 0 | } |
855 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
856 | |
|
857 | 0 | p = skip_string(param,tpscnt,p); |
858 | 0 | if (!p) { |
859 | 0 | return False; |
860 | 0 | } |
861 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
862 | 0 | str3 = get_safe_str_ptr(param,tpscnt,p,4); |
863 | | /* str3 may be null here and is checked in check_printq_info(). */ |
864 | | |
865 | | /* remove any trailing username */ |
866 | 0 | if ((p = strchr_m(QueueName,'%'))) |
867 | 0 | *p = 0; |
868 | |
|
869 | 0 | DEBUG(3,("api_DosPrintQGetInfo uLevel=%d name=%s\n",uLevel,QueueName)); |
870 | | |
871 | | /* check it's a supported variant */ |
872 | 0 | if (!prefix_ok(str1,"zWrLh")) |
873 | 0 | return False; |
874 | 0 | if (!check_printq_info(&desc,uLevel,str2,str3)) { |
875 | | /* |
876 | | * Patch from Scott Moomaw <scott@bridgewater.edu> |
877 | | * to return the 'invalid info level' error if an |
878 | | * unknown level was requested. |
879 | | */ |
880 | 0 | *rdata_len = 0; |
881 | 0 | *rparam_len = 6; |
882 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
883 | 0 | if (!*rparam) { |
884 | 0 | return False; |
885 | 0 | } |
886 | 0 | SSVALS(*rparam,0,ERRunknownlevel); |
887 | 0 | SSVAL(*rparam,2,0); |
888 | 0 | SSVAL(*rparam,4,0); |
889 | 0 | return(True); |
890 | 0 | } |
891 | | |
892 | 0 | ZERO_STRUCT(handle); |
893 | |
|
894 | 0 | if (QueueName == NULL || (strlen(QueueName) < 1)) { |
895 | 0 | desc.errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
896 | 0 | goto out; |
897 | 0 | } |
898 | | |
899 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
900 | 0 | &ndr_table_spoolss, |
901 | 0 | conn->session_info, |
902 | 0 | conn->sconn->remote_address, |
903 | 0 | conn->sconn->local_address, |
904 | 0 | conn->sconn->msg_ctx, |
905 | 0 | &cli); |
906 | 0 | if (!NT_STATUS_IS_OK(status)) { |
907 | 0 | DEBUG(0,("api_DosPrintQGetInfo: could not connect to spoolss: %s\n", |
908 | 0 | nt_errstr(status))); |
909 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
910 | 0 | goto out; |
911 | 0 | } |
912 | 0 | b = cli->binding_handle; |
913 | |
|
914 | 0 | ZERO_STRUCT(devmode_ctr); |
915 | |
|
916 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
917 | 0 | QueueName, |
918 | 0 | "RAW", |
919 | 0 | devmode_ctr, |
920 | 0 | PRINTER_ACCESS_USE, |
921 | 0 | &handle, |
922 | 0 | &werr); |
923 | 0 | if (!NT_STATUS_IS_OK(status)) { |
924 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
925 | 0 | goto out; |
926 | 0 | } |
927 | 0 | if (!W_ERROR_IS_OK(werr)) { |
928 | 0 | desc.errcode = W_ERROR_V(werr); |
929 | 0 | goto out; |
930 | 0 | } |
931 | | |
932 | 0 | werr = rpccli_spoolss_getprinter(cli, mem_ctx, |
933 | 0 | &handle, |
934 | 0 | 2, |
935 | 0 | 0, |
936 | 0 | &printer_info); |
937 | 0 | if (!W_ERROR_IS_OK(werr)) { |
938 | 0 | desc.errcode = W_ERROR_V(werr); |
939 | 0 | goto out; |
940 | 0 | } |
941 | | |
942 | 0 | if (uLevel==52) { |
943 | 0 | uint32_t server_major_version; |
944 | 0 | uint32_t server_minor_version; |
945 | |
|
946 | 0 | werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx, |
947 | 0 | &handle, |
948 | 0 | "Windows 4.0", |
949 | 0 | 3, /* level */ |
950 | 0 | 0, |
951 | 0 | 0, /* version */ |
952 | 0 | 0, |
953 | 0 | &driver_info, |
954 | 0 | &server_major_version, |
955 | 0 | &server_minor_version); |
956 | 0 | if (!W_ERROR_IS_OK(werr)) { |
957 | 0 | desc.errcode = W_ERROR_V(werr); |
958 | 0 | goto out; |
959 | 0 | } |
960 | | |
961 | 0 | count = get_printerdrivernumber(&driver_info.info3); |
962 | 0 | DEBUG(3,("api_DosPrintQGetInfo: Driver files count: %d\n",count)); |
963 | 0 | } else { |
964 | 0 | uint32_t num_jobs; |
965 | 0 | werr = rpccli_spoolss_enumjobs(cli, mem_ctx, |
966 | 0 | &handle, |
967 | 0 | 0, /* firstjob */ |
968 | 0 | 0xff, /* numjobs */ |
969 | 0 | 2, /* level */ |
970 | 0 | 0, /* offered */ |
971 | 0 | &num_jobs, |
972 | 0 | &job_info); |
973 | 0 | if (!W_ERROR_IS_OK(werr)) { |
974 | 0 | desc.errcode = W_ERROR_V(werr); |
975 | 0 | goto out; |
976 | 0 | } |
977 | | |
978 | 0 | count = num_jobs; |
979 | 0 | } |
980 | | |
981 | 0 | if (mdrcnt > 0) { |
982 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
983 | 0 | if (!*rdata) { |
984 | 0 | return False; |
985 | 0 | } |
986 | 0 | desc.base = *rdata; |
987 | 0 | desc.buflen = mdrcnt; |
988 | 0 | } else { |
989 | | /* |
990 | | * Don't return data but need to get correct length |
991 | | * init_package will return wrong size if buflen=0 |
992 | | */ |
993 | 0 | desc.buflen = getlen(desc.format); |
994 | 0 | desc.base = tmpdata = (char *) SMB_MALLOC (desc.buflen); |
995 | 0 | } |
996 | | |
997 | 0 | if (init_package(&desc,1,count)) { |
998 | 0 | desc.subcount = count; |
999 | 0 | fill_printq_info(uLevel,&desc,count, job_info, &driver_info.info3, &printer_info.info2); |
1000 | 0 | } |
1001 | |
|
1002 | 0 | *rdata_len = desc.usedlen; |
1003 | | |
1004 | | /* |
1005 | | * We must set the return code to ERRbuftoosmall |
1006 | | * in order to support lanman style printing with Win NT/2k |
1007 | | * clients --jerry |
1008 | | */ |
1009 | 0 | if (!mdrcnt && lp_disable_spoolss()) |
1010 | 0 | desc.errcode = ERRbuftoosmall; |
1011 | |
|
1012 | 0 | out: |
1013 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
1014 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
1015 | 0 | } |
1016 | |
|
1017 | 0 | *rdata_len = desc.usedlen; |
1018 | 0 | *rparam_len = 6; |
1019 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1020 | 0 | if (!*rparam) { |
1021 | 0 | SAFE_FREE(tmpdata); |
1022 | 0 | return False; |
1023 | 0 | } |
1024 | 0 | SSVALS(*rparam,0,desc.errcode); |
1025 | 0 | SSVAL(*rparam,2,0); |
1026 | 0 | SSVAL(*rparam,4,desc.neededlen); |
1027 | |
|
1028 | 0 | DEBUG(4,("printqgetinfo: errorcode %d\n",desc.errcode)); |
1029 | |
|
1030 | 0 | SAFE_FREE(tmpdata); |
1031 | |
|
1032 | 0 | return(True); |
1033 | 0 | } |
1034 | | |
1035 | | /**************************************************************************** |
1036 | | View list of all print jobs on all queues. |
1037 | | ****************************************************************************/ |
1038 | | |
1039 | | static bool api_DosPrintQEnum(struct smbd_server_connection *sconn, |
1040 | | connection_struct *conn, uint64_t vuid, |
1041 | | char *param, int tpscnt, |
1042 | | char *data, int tdscnt, |
1043 | | int mdrcnt, int mprcnt, |
1044 | | char **rdata, char** rparam, |
1045 | | int *rdata_len, int *rparam_len) |
1046 | 0 | { |
1047 | 0 | char *param_format = get_safe_str_ptr(param,tpscnt,param,2); |
1048 | 0 | char *output_format1 = skip_string(param,tpscnt,param_format); |
1049 | 0 | char *p = skip_string(param,tpscnt,output_format1); |
1050 | 0 | unsigned int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
1051 | 0 | char *output_format2 = get_safe_str_ptr(param,tpscnt,p,4); |
1052 | 0 | int i; |
1053 | 0 | struct pack_desc desc; |
1054 | 0 | int *subcntarr = NULL; |
1055 | 0 | int queuecnt = 0, subcnt = 0, succnt = 0; |
1056 | |
|
1057 | 0 | WERROR werr = WERR_OK; |
1058 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
1059 | 0 | NTSTATUS status; |
1060 | 0 | struct rpc_pipe_client *cli = NULL; |
1061 | 0 | struct dcerpc_binding_handle *b = NULL; |
1062 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
1063 | 0 | uint32_t num_printers; |
1064 | 0 | union spoolss_PrinterInfo *printer_info; |
1065 | 0 | union spoolss_DriverInfo *driver_info; |
1066 | 0 | union spoolss_JobInfo **job_info; |
1067 | |
|
1068 | 0 | if (!param_format || !output_format1 || !p) { |
1069 | 0 | return False; |
1070 | 0 | } |
1071 | | |
1072 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
1073 | |
|
1074 | 0 | DEBUG(3,("DosPrintQEnum uLevel=%d\n",uLevel)); |
1075 | |
|
1076 | 0 | if (!prefix_ok(param_format,"WrLeh")) { |
1077 | 0 | return False; |
1078 | 0 | } |
1079 | 0 | if (!check_printq_info(&desc,uLevel,output_format1,output_format2)) { |
1080 | | /* |
1081 | | * Patch from Scott Moomaw <scott@bridgewater.edu> |
1082 | | * to return the 'invalid info level' error if an |
1083 | | * unknown level was requested. |
1084 | | */ |
1085 | 0 | *rdata_len = 0; |
1086 | 0 | *rparam_len = 6; |
1087 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1088 | 0 | if (!*rparam) { |
1089 | 0 | return False; |
1090 | 0 | } |
1091 | 0 | SSVALS(*rparam,0,ERRunknownlevel); |
1092 | 0 | SSVAL(*rparam,2,0); |
1093 | 0 | SSVAL(*rparam,4,0); |
1094 | 0 | return(True); |
1095 | 0 | } |
1096 | | |
1097 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
1098 | 0 | &ndr_table_spoolss, |
1099 | 0 | conn->session_info, |
1100 | 0 | conn->sconn->remote_address, |
1101 | 0 | conn->sconn->local_address, |
1102 | 0 | conn->sconn->msg_ctx, |
1103 | 0 | &cli); |
1104 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1105 | 0 | DEBUG(0,("api_DosPrintQEnum: could not connect to spoolss: %s\n", |
1106 | 0 | nt_errstr(status))); |
1107 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
1108 | 0 | goto out; |
1109 | 0 | } |
1110 | 0 | b = cli->binding_handle; |
1111 | |
|
1112 | 0 | werr = rpccli_spoolss_enumprinters(cli, mem_ctx, |
1113 | 0 | PRINTER_ENUM_LOCAL, |
1114 | 0 | cli->srv_name_slash, |
1115 | 0 | 2, |
1116 | 0 | 0, |
1117 | 0 | &num_printers, |
1118 | 0 | &printer_info); |
1119 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1120 | 0 | desc.errcode = W_ERROR_V(werr); |
1121 | 0 | goto out; |
1122 | 0 | } |
1123 | | |
1124 | 0 | queuecnt = num_printers; |
1125 | |
|
1126 | 0 | job_info = talloc_array(mem_ctx, union spoolss_JobInfo *, num_printers); |
1127 | 0 | if (job_info == NULL) { |
1128 | 0 | goto err; |
1129 | 0 | } |
1130 | | |
1131 | 0 | driver_info = talloc_array(mem_ctx, union spoolss_DriverInfo, num_printers); |
1132 | 0 | if (driver_info == NULL) { |
1133 | 0 | goto err; |
1134 | 0 | } |
1135 | | |
1136 | 0 | if((subcntarr = SMB_MALLOC_ARRAY(int,queuecnt)) == NULL) { |
1137 | 0 | DEBUG(0,("api_DosPrintQEnum: malloc fail !\n")); |
1138 | 0 | goto err; |
1139 | 0 | } |
1140 | | |
1141 | 0 | if (mdrcnt > 0) { |
1142 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
1143 | 0 | if (!*rdata) { |
1144 | 0 | goto err; |
1145 | 0 | } |
1146 | 0 | } |
1147 | 0 | desc.base = *rdata; |
1148 | 0 | desc.buflen = mdrcnt; |
1149 | |
|
1150 | 0 | subcnt = 0; |
1151 | 0 | for (i = 0; i < num_printers; i++) { |
1152 | |
|
1153 | 0 | uint32_t num_jobs; |
1154 | 0 | struct policy_handle handle; |
1155 | 0 | const char *printername; |
1156 | |
|
1157 | 0 | printername = talloc_strdup(mem_ctx, printer_info[i].info2.printername); |
1158 | 0 | if (printername == NULL) { |
1159 | 0 | goto err; |
1160 | 0 | } |
1161 | | |
1162 | 0 | ZERO_STRUCT(handle); |
1163 | 0 | ZERO_STRUCT(devmode_ctr); |
1164 | |
|
1165 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
1166 | 0 | printername, |
1167 | 0 | "RAW", |
1168 | 0 | devmode_ctr, |
1169 | 0 | PRINTER_ACCESS_USE, |
1170 | 0 | &handle, |
1171 | 0 | &werr); |
1172 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1173 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
1174 | 0 | goto out; |
1175 | 0 | } |
1176 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1177 | 0 | desc.errcode = W_ERROR_V(werr); |
1178 | 0 | goto out; |
1179 | 0 | } |
1180 | | |
1181 | 0 | werr = rpccli_spoolss_enumjobs(cli, mem_ctx, |
1182 | 0 | &handle, |
1183 | 0 | 0, /* firstjob */ |
1184 | 0 | 0xff, /* numjobs */ |
1185 | 0 | 2, /* level */ |
1186 | 0 | 0, /* offered */ |
1187 | 0 | &num_jobs, |
1188 | 0 | &job_info[i]); |
1189 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1190 | 0 | desc.errcode = W_ERROR_V(werr); |
1191 | 0 | goto out; |
1192 | 0 | } |
1193 | | |
1194 | 0 | if (uLevel==52) { |
1195 | 0 | uint32_t server_major_version; |
1196 | 0 | uint32_t server_minor_version; |
1197 | |
|
1198 | 0 | werr = rpccli_spoolss_getprinterdriver2(cli, mem_ctx, |
1199 | 0 | &handle, |
1200 | 0 | "Windows 4.0", |
1201 | 0 | 3, /* level */ |
1202 | 0 | 0, |
1203 | 0 | 0, /* version */ |
1204 | 0 | 0, |
1205 | 0 | &driver_info[i], |
1206 | 0 | &server_major_version, |
1207 | 0 | &server_minor_version); |
1208 | 0 | if (!W_ERROR_IS_OK(werr)) { |
1209 | 0 | desc.errcode = W_ERROR_V(werr); |
1210 | 0 | goto out; |
1211 | 0 | } |
1212 | 0 | } |
1213 | | |
1214 | 0 | subcntarr[i] = num_jobs; |
1215 | 0 | subcnt += subcntarr[i]; |
1216 | |
|
1217 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
1218 | 0 | } |
1219 | | |
1220 | 0 | if (init_package(&desc,queuecnt,subcnt)) { |
1221 | 0 | for (i = 0; i < num_printers; i++) { |
1222 | 0 | fill_printq_info(uLevel,&desc,subcntarr[i], job_info[i], &driver_info[i].info3, &printer_info[i].info2); |
1223 | 0 | if (desc.errcode == NERR_Success) { |
1224 | 0 | succnt = i; |
1225 | 0 | } |
1226 | 0 | } |
1227 | 0 | } |
1228 | |
|
1229 | 0 | out: |
1230 | 0 | SAFE_FREE(subcntarr); |
1231 | 0 | *rdata_len = desc.usedlen; |
1232 | 0 | *rparam_len = 8; |
1233 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1234 | 0 | if (!*rparam) { |
1235 | 0 | goto err; |
1236 | 0 | } |
1237 | 0 | SSVALS(*rparam,0,desc.errcode); |
1238 | 0 | SSVAL(*rparam,2,0); |
1239 | 0 | SSVAL(*rparam,4,succnt); |
1240 | 0 | SSVAL(*rparam,6,queuecnt); |
1241 | |
|
1242 | 0 | return True; |
1243 | | |
1244 | 0 | err: |
1245 | |
|
1246 | 0 | SAFE_FREE(subcntarr); |
1247 | |
|
1248 | 0 | return False; |
1249 | 0 | } |
1250 | | |
1251 | | /**************************************************************************** |
1252 | | Get info level for a server list query. |
1253 | | ****************************************************************************/ |
1254 | | |
1255 | | static bool check_session_info(int uLevel, char* id) |
1256 | 0 | { |
1257 | 0 | switch( uLevel ) { |
1258 | 0 | case 0: |
1259 | 0 | if (strcmp(id,"B16") != 0) { |
1260 | 0 | return False; |
1261 | 0 | } |
1262 | 0 | break; |
1263 | 0 | case 1: |
1264 | 0 | if (strcmp(id,"B16BBDz") != 0) { |
1265 | 0 | return False; |
1266 | 0 | } |
1267 | 0 | break; |
1268 | 0 | default: |
1269 | 0 | return False; |
1270 | 0 | } |
1271 | 0 | return True; |
1272 | 0 | } |
1273 | | |
1274 | | struct srv_info_struct { |
1275 | | fstring name; |
1276 | | uint32_t type; |
1277 | | fstring comment; |
1278 | | fstring domain; |
1279 | | bool server_added; |
1280 | | }; |
1281 | | |
1282 | | /******************************************************************* |
1283 | | Get server info lists from the files saved by nmbd. Return the |
1284 | | number of entries. |
1285 | | ******************************************************************/ |
1286 | | |
1287 | | static int get_session_info(uint32_t servertype, |
1288 | | struct srv_info_struct **servers, |
1289 | | const char *domain) |
1290 | 0 | { |
1291 | 0 | int count=0; |
1292 | 0 | int alloced=0; |
1293 | 0 | char **lines; |
1294 | 0 | bool local_list_only; |
1295 | 0 | int i; |
1296 | 0 | char *slist_cache_path = cache_path(talloc_tos(), SERVER_LIST); |
1297 | 0 | if (slist_cache_path == NULL) { |
1298 | 0 | return 0; |
1299 | 0 | } |
1300 | | |
1301 | 0 | lines = file_lines_load(slist_cache_path, NULL, 0, NULL); |
1302 | 0 | if (!lines) { |
1303 | 0 | DEBUG(4, ("Can't open %s - %s\n", |
1304 | 0 | slist_cache_path, strerror(errno))); |
1305 | 0 | TALLOC_FREE(slist_cache_path); |
1306 | 0 | return 0; |
1307 | 0 | } |
1308 | 0 | TALLOC_FREE(slist_cache_path); |
1309 | | |
1310 | | /* request for everything is code for request all servers */ |
1311 | 0 | if (servertype == SV_TYPE_ALL) { |
1312 | 0 | servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); |
1313 | 0 | } |
1314 | |
|
1315 | 0 | local_list_only = (servertype & SV_TYPE_LOCAL_LIST_ONLY); |
1316 | |
|
1317 | 0 | DEBUG(4,("Servertype search: %8x\n",servertype)); |
1318 | |
|
1319 | 0 | for (i=0;lines[i];i++) { |
1320 | 0 | fstring stype; |
1321 | 0 | struct srv_info_struct *s; |
1322 | 0 | const char *ptr = lines[i]; |
1323 | 0 | bool ok = True; |
1324 | 0 | TALLOC_CTX *frame = NULL; |
1325 | 0 | char *p; |
1326 | |
|
1327 | 0 | if (!*ptr) { |
1328 | 0 | continue; |
1329 | 0 | } |
1330 | | |
1331 | 0 | if (count == alloced) { |
1332 | 0 | alloced += 10; |
1333 | 0 | *servers = SMB_REALLOC_ARRAY(*servers,struct srv_info_struct, alloced); |
1334 | 0 | if (!*servers) { |
1335 | 0 | DEBUG(0,("get_session_info: failed to enlarge servers info struct!\n")); |
1336 | 0 | TALLOC_FREE(lines); |
1337 | 0 | return 0; |
1338 | 0 | } |
1339 | 0 | memset((char *)((*servers)+count),'\0',sizeof(**servers)*(alloced-count)); |
1340 | 0 | } |
1341 | 0 | s = &(*servers)[count]; |
1342 | |
|
1343 | 0 | frame = talloc_stackframe(); |
1344 | 0 | s->name[0] = '\0'; |
1345 | 0 | if (!next_token_talloc(frame,&ptr,&p, NULL)) { |
1346 | 0 | TALLOC_FREE(frame); |
1347 | 0 | continue; |
1348 | 0 | } |
1349 | 0 | fstrcpy(s->name, p); |
1350 | |
|
1351 | 0 | stype[0] = '\0'; |
1352 | 0 | if (!next_token_talloc(frame,&ptr, &p, NULL)) { |
1353 | 0 | TALLOC_FREE(frame); |
1354 | 0 | continue; |
1355 | 0 | } |
1356 | 0 | fstrcpy(stype, p); |
1357 | |
|
1358 | 0 | s->comment[0] = '\0'; |
1359 | 0 | if (!next_token_talloc(frame,&ptr, &p, NULL)) { |
1360 | 0 | TALLOC_FREE(frame); |
1361 | 0 | continue; |
1362 | 0 | } |
1363 | 0 | fstrcpy(s->comment, p); |
1364 | 0 | string_truncate(s->comment, MAX_SERVER_STRING_LENGTH); |
1365 | |
|
1366 | 0 | s->domain[0] = '\0'; |
1367 | 0 | if (!next_token_talloc(frame,&ptr,&p, NULL)) { |
1368 | | /* this allows us to cope with an old nmbd */ |
1369 | 0 | fstrcpy(s->domain,lp_workgroup()); |
1370 | 0 | } else { |
1371 | 0 | fstrcpy(s->domain, p); |
1372 | 0 | } |
1373 | 0 | TALLOC_FREE(frame); |
1374 | |
|
1375 | 0 | if (sscanf(stype,"%X",&s->type) != 1) { |
1376 | 0 | DEBUG(4,("r:host file ")); |
1377 | 0 | ok = False; |
1378 | 0 | } |
1379 | | |
1380 | | /* Filter the servers/domains we return based on what was asked for. */ |
1381 | | |
1382 | | /* Check to see if we are being asked for a local list only. */ |
1383 | 0 | if(local_list_only && ((s->type & SV_TYPE_LOCAL_LIST_ONLY) == 0)) { |
1384 | 0 | DEBUG(4,("r: local list only")); |
1385 | 0 | ok = False; |
1386 | 0 | } |
1387 | | |
1388 | | /* doesn't match up: don't want it */ |
1389 | 0 | if (!(servertype & s->type)) { |
1390 | 0 | DEBUG(4,("r:serv type ")); |
1391 | 0 | ok = False; |
1392 | 0 | } |
1393 | |
|
1394 | 0 | if ((servertype & SV_TYPE_DOMAIN_ENUM) != |
1395 | 0 | (s->type & SV_TYPE_DOMAIN_ENUM)) { |
1396 | 0 | DEBUG(4,("s: dom mismatch ")); |
1397 | 0 | ok = False; |
1398 | 0 | } |
1399 | |
|
1400 | 0 | if (!strequal(domain, s->domain) && !(servertype & SV_TYPE_DOMAIN_ENUM)) { |
1401 | 0 | ok = False; |
1402 | 0 | } |
1403 | | |
1404 | | /* We should never return a server type with a SV_TYPE_LOCAL_LIST_ONLY set. */ |
1405 | 0 | s->type &= ~SV_TYPE_LOCAL_LIST_ONLY; |
1406 | |
|
1407 | 0 | if (ok) { |
1408 | 0 | DEBUG(4,("**SV** %20s %8x %25s %15s\n", |
1409 | 0 | s->name, s->type, s->comment, s->domain)); |
1410 | 0 | s->server_added = True; |
1411 | 0 | count++; |
1412 | 0 | } else { |
1413 | 0 | DEBUG(4,("%20s %8x %25s %15s\n", |
1414 | 0 | s->name, s->type, s->comment, s->domain)); |
1415 | 0 | } |
1416 | 0 | } |
1417 | | |
1418 | 0 | TALLOC_FREE(lines); |
1419 | 0 | return count; |
1420 | 0 | } |
1421 | | |
1422 | | /******************************************************************* |
1423 | | Fill in a server info structure. |
1424 | | ******************************************************************/ |
1425 | | |
1426 | | static int fill_srv_info(struct srv_info_struct *service, |
1427 | | int uLevel, char **buf, int *buflen, |
1428 | | char **stringbuf, int *stringspace, char *baseaddr) |
1429 | 0 | { |
1430 | 0 | int struct_len; |
1431 | 0 | char* p; |
1432 | 0 | char* p2; |
1433 | 0 | int l2; |
1434 | 0 | int len; |
1435 | |
|
1436 | 0 | switch (uLevel) { |
1437 | 0 | case 0: |
1438 | 0 | struct_len = 16; |
1439 | 0 | break; |
1440 | 0 | case 1: |
1441 | 0 | struct_len = 26; |
1442 | 0 | break; |
1443 | 0 | default: |
1444 | 0 | return -1; |
1445 | 0 | } |
1446 | | |
1447 | 0 | if (!buf) { |
1448 | 0 | len = 0; |
1449 | 0 | switch (uLevel) { |
1450 | 0 | case 1: |
1451 | 0 | len = strlen(service->comment)+1; |
1452 | 0 | break; |
1453 | 0 | } |
1454 | | |
1455 | 0 | *buflen = struct_len; |
1456 | 0 | *stringspace = len; |
1457 | 0 | return struct_len + len; |
1458 | 0 | } |
1459 | | |
1460 | 0 | len = struct_len; |
1461 | 0 | p = *buf; |
1462 | 0 | if (*buflen < struct_len) { |
1463 | 0 | return -1; |
1464 | 0 | } |
1465 | 0 | if (stringbuf) { |
1466 | 0 | p2 = *stringbuf; |
1467 | 0 | l2 = *stringspace; |
1468 | 0 | } else { |
1469 | 0 | p2 = p + struct_len; |
1470 | 0 | l2 = *buflen - struct_len; |
1471 | 0 | } |
1472 | 0 | if (!baseaddr) { |
1473 | 0 | baseaddr = p; |
1474 | 0 | } |
1475 | |
|
1476 | 0 | switch (uLevel) { |
1477 | 0 | case 0: |
1478 | 0 | push_ascii(p,service->name, MAX_NETBIOSNAME_LEN, STR_TERMINATE); |
1479 | 0 | break; |
1480 | | |
1481 | 0 | case 1: |
1482 | 0 | push_ascii(p,service->name,MAX_NETBIOSNAME_LEN, STR_TERMINATE); |
1483 | 0 | SIVAL(p,18,service->type); |
1484 | 0 | SIVAL(p,22,PTR_DIFF(p2,baseaddr)); |
1485 | 0 | len += CopyAndAdvance(&p2,service->comment,&l2); |
1486 | 0 | break; |
1487 | 0 | } |
1488 | | |
1489 | 0 | if (stringbuf) { |
1490 | 0 | *buf = p + struct_len; |
1491 | 0 | *buflen -= struct_len; |
1492 | 0 | *stringbuf = p2; |
1493 | 0 | *stringspace = l2; |
1494 | 0 | } else { |
1495 | 0 | *buf = p2; |
1496 | 0 | *buflen -= len; |
1497 | 0 | } |
1498 | 0 | return len; |
1499 | 0 | } |
1500 | | |
1501 | | |
1502 | | static int srv_comp(struct srv_info_struct *s1,struct srv_info_struct *s2) |
1503 | 0 | { |
1504 | 0 | return strcasecmp_m(s1->name,s2->name); |
1505 | 0 | } |
1506 | | |
1507 | | /**************************************************************************** |
1508 | | View list of servers available (or possibly domains). The info is |
1509 | | extracted from lists saved by nmbd on the local host. |
1510 | | ****************************************************************************/ |
1511 | | |
1512 | | static bool api_RNetServerEnum2(struct smbd_server_connection *sconn, |
1513 | | connection_struct *conn, uint64_t vuid, |
1514 | | char *param, int tpscnt, |
1515 | | char *data, int tdscnt, |
1516 | | int mdrcnt, int mprcnt, char **rdata, |
1517 | | char **rparam, int *rdata_len, int *rparam_len) |
1518 | 0 | { |
1519 | 0 | char *str1 = get_safe_str_ptr(param, tpscnt, param, 2); |
1520 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
1521 | 0 | char *p = skip_string(param,tpscnt,str2); |
1522 | 0 | int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1); |
1523 | 0 | int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0); |
1524 | 0 | uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0); |
1525 | 0 | char *p2; |
1526 | 0 | int data_len, fixed_len, string_len; |
1527 | 0 | int f_len = 0, s_len = 0; |
1528 | 0 | struct srv_info_struct *servers=NULL; |
1529 | 0 | int counted=0,total=0; |
1530 | 0 | int i,missed; |
1531 | 0 | fstring domain; |
1532 | 0 | bool domain_request; |
1533 | 0 | bool local_request; |
1534 | |
|
1535 | 0 | if (!str1 || !str2 || !p) { |
1536 | 0 | return False; |
1537 | 0 | } |
1538 | | |
1539 | | /* If someone sets all the bits they don't really mean to set |
1540 | | DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the |
1541 | | known servers. */ |
1542 | | |
1543 | 0 | if (servertype == SV_TYPE_ALL) { |
1544 | 0 | servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); |
1545 | 0 | } |
1546 | | |
1547 | | /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set |
1548 | | any other bit (they may just set this bit on its own) they |
1549 | | want all the locally seen servers. However this bit can be |
1550 | | set on its own so set the requested servers to be |
1551 | | ALL - DOMAIN_ENUM. */ |
1552 | |
|
1553 | 0 | if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) { |
1554 | 0 | servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); |
1555 | 0 | } |
1556 | |
|
1557 | 0 | domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); |
1558 | 0 | local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); |
1559 | |
|
1560 | 0 | p += 8; |
1561 | |
|
1562 | 0 | if (!prefix_ok(str1,"WrLehD")) { |
1563 | 0 | return False; |
1564 | 0 | } |
1565 | 0 | if (!check_session_info(uLevel,str2)) { |
1566 | 0 | return False; |
1567 | 0 | } |
1568 | | |
1569 | 0 | DEBUG(4, ("server request level: %s %8x ", str2, servertype)); |
1570 | 0 | DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); |
1571 | 0 | DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); |
1572 | |
|
1573 | 0 | if (strcmp(str1, "WrLehDz") == 0) { |
1574 | 0 | if (skip_string(param,tpscnt,p) == NULL) { |
1575 | 0 | return False; |
1576 | 0 | } |
1577 | 0 | pull_ascii_fstring(domain, p); |
1578 | 0 | } else { |
1579 | 0 | fstrcpy(domain, lp_workgroup()); |
1580 | 0 | } |
1581 | | |
1582 | 0 | DEBUG(4, ("domain [%s]\n", domain)); |
1583 | |
|
1584 | 0 | if (lp_browse_list()) { |
1585 | 0 | total = get_session_info(servertype,&servers,domain); |
1586 | 0 | } |
1587 | |
|
1588 | 0 | data_len = fixed_len = string_len = 0; |
1589 | 0 | missed = 0; |
1590 | |
|
1591 | 0 | TYPESAFE_QSORT(servers, total, srv_comp); |
1592 | |
|
1593 | 0 | { |
1594 | 0 | char *lastname=NULL; |
1595 | |
|
1596 | 0 | for (i=0;i<total;i++) { |
1597 | 0 | struct srv_info_struct *s = &servers[i]; |
1598 | |
|
1599 | 0 | if (lastname && strequal(lastname,s->name)) { |
1600 | 0 | continue; |
1601 | 0 | } |
1602 | 0 | lastname = s->name; |
1603 | 0 | data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); |
1604 | 0 | DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n", |
1605 | 0 | i, s->name, s->type, s->comment, s->domain)); |
1606 | |
|
1607 | 0 | if (data_len < buf_len) { |
1608 | 0 | counted++; |
1609 | 0 | fixed_len += f_len; |
1610 | 0 | string_len += s_len; |
1611 | 0 | } else { |
1612 | 0 | missed++; |
1613 | 0 | } |
1614 | 0 | } |
1615 | 0 | } |
1616 | |
|
1617 | 0 | *rdata_len = fixed_len + string_len; |
1618 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
1619 | 0 | if (!*rdata) { |
1620 | 0 | return False; |
1621 | 0 | } |
1622 | | |
1623 | 0 | p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ |
1624 | 0 | p = *rdata; |
1625 | 0 | f_len = fixed_len; |
1626 | 0 | s_len = string_len; |
1627 | |
|
1628 | 0 | { |
1629 | 0 | char *lastname=NULL; |
1630 | 0 | int count2 = counted; |
1631 | |
|
1632 | 0 | for (i = 0; i < total && count2;i++) { |
1633 | 0 | struct srv_info_struct *s = &servers[i]; |
1634 | |
|
1635 | 0 | if (lastname && strequal(lastname,s->name)) { |
1636 | 0 | continue; |
1637 | 0 | } |
1638 | 0 | lastname = s->name; |
1639 | 0 | fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); |
1640 | 0 | DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n", |
1641 | 0 | i, s->name, s->type, s->comment, s->domain)); |
1642 | 0 | count2--; |
1643 | 0 | } |
1644 | 0 | } |
1645 | |
|
1646 | 0 | *rparam_len = 8; |
1647 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1648 | 0 | if (!*rparam) { |
1649 | 0 | return False; |
1650 | 0 | } |
1651 | 0 | SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata)); |
1652 | 0 | SSVAL(*rparam,2,0); |
1653 | 0 | SSVAL(*rparam,4,counted); |
1654 | 0 | SSVAL(*rparam,6,counted+missed); |
1655 | |
|
1656 | 0 | SAFE_FREE(servers); |
1657 | |
|
1658 | 0 | DEBUG(3,("NetServerEnum2 domain = %s uLevel=%d counted=%d total=%d\n", |
1659 | 0 | domain,uLevel,counted,counted+missed)); |
1660 | |
|
1661 | 0 | return True; |
1662 | 0 | } |
1663 | | |
1664 | | static int srv_name_match(const char *n1, const char *n2) |
1665 | 0 | { |
1666 | | /* |
1667 | | * [MS-RAP] footnote <88> for Section 3.2.5.15 says: |
1668 | | * |
1669 | | * In Windows, FirstNameToReturn need not be an exact match: |
1670 | | * the server will return a list of servers that exist on |
1671 | | * the network greater than or equal to the FirstNameToReturn. |
1672 | | */ |
1673 | 0 | int ret = strcasecmp_m(n1, n2); |
1674 | |
|
1675 | 0 | if (ret <= 0) { |
1676 | 0 | return 0; |
1677 | 0 | } |
1678 | | |
1679 | 0 | return ret; |
1680 | 0 | } |
1681 | | |
1682 | | static bool api_RNetServerEnum3(struct smbd_server_connection *sconn, |
1683 | | connection_struct *conn, uint64_t vuid, |
1684 | | char *param, int tpscnt, |
1685 | | char *data, int tdscnt, |
1686 | | int mdrcnt, int mprcnt, char **rdata, |
1687 | | char **rparam, int *rdata_len, int *rparam_len) |
1688 | 0 | { |
1689 | 0 | char *str1 = get_safe_str_ptr(param, tpscnt, param, 2); |
1690 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
1691 | 0 | char *p = skip_string(param,tpscnt,str2); |
1692 | 0 | int uLevel = get_safe_SVAL(param, tpscnt, p, 0, -1); |
1693 | 0 | int buf_len = get_safe_SVAL(param,tpscnt, p, 2, 0); |
1694 | 0 | uint32_t servertype = get_safe_IVAL(param,tpscnt,p,4, 0); |
1695 | 0 | char *p2; |
1696 | 0 | int data_len, fixed_len, string_len; |
1697 | 0 | int f_len = 0, s_len = 0; |
1698 | 0 | struct srv_info_struct *servers=NULL; |
1699 | 0 | int counted=0,first=0,total=0; |
1700 | 0 | int i,missed; |
1701 | 0 | fstring domain; |
1702 | 0 | fstring first_name; |
1703 | 0 | bool domain_request; |
1704 | 0 | bool local_request; |
1705 | |
|
1706 | 0 | if (!str1 || !str2 || !p) { |
1707 | 0 | return False; |
1708 | 0 | } |
1709 | | |
1710 | | /* If someone sets all the bits they don't really mean to set |
1711 | | DOMAIN_ENUM and LOCAL_LIST_ONLY, they just want all the |
1712 | | known servers. */ |
1713 | | |
1714 | 0 | if (servertype == SV_TYPE_ALL) { |
1715 | 0 | servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY); |
1716 | 0 | } |
1717 | | |
1718 | | /* If someone sets SV_TYPE_LOCAL_LIST_ONLY but hasn't set |
1719 | | any other bit (they may just set this bit on its own) they |
1720 | | want all the locally seen servers. However this bit can be |
1721 | | set on its own so set the requested servers to be |
1722 | | ALL - DOMAIN_ENUM. */ |
1723 | |
|
1724 | 0 | if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) && !(servertype & SV_TYPE_DOMAIN_ENUM)) { |
1725 | 0 | servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM); |
1726 | 0 | } |
1727 | |
|
1728 | 0 | domain_request = ((servertype & SV_TYPE_DOMAIN_ENUM) != 0); |
1729 | 0 | local_request = ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0); |
1730 | |
|
1731 | 0 | p += 8; |
1732 | |
|
1733 | 0 | if (strcmp(str1, "WrLehDzz") != 0) { |
1734 | 0 | return false; |
1735 | 0 | } |
1736 | 0 | if (!check_session_info(uLevel,str2)) { |
1737 | 0 | return False; |
1738 | 0 | } |
1739 | | |
1740 | 0 | DEBUG(4, ("server request level: %s %8x ", str2, servertype)); |
1741 | 0 | DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); |
1742 | 0 | DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); |
1743 | |
|
1744 | 0 | if (skip_string(param,tpscnt,p) == NULL) { |
1745 | 0 | return False; |
1746 | 0 | } |
1747 | 0 | pull_ascii_fstring(domain, p); |
1748 | 0 | if (domain[0] == '\0') { |
1749 | 0 | fstrcpy(domain, lp_workgroup()); |
1750 | 0 | } |
1751 | 0 | p = skip_string(param,tpscnt,p); |
1752 | 0 | if (skip_string(param,tpscnt,p) == NULL) { |
1753 | 0 | return False; |
1754 | 0 | } |
1755 | 0 | pull_ascii_fstring(first_name, p); |
1756 | |
|
1757 | 0 | DEBUG(4, ("domain: '%s' first_name: '%s'\n", |
1758 | 0 | domain, first_name)); |
1759 | |
|
1760 | 0 | if (lp_browse_list()) { |
1761 | 0 | total = get_session_info(servertype,&servers,domain); |
1762 | 0 | } |
1763 | |
|
1764 | 0 | data_len = fixed_len = string_len = 0; |
1765 | 0 | missed = 0; |
1766 | |
|
1767 | 0 | TYPESAFE_QSORT(servers, total, srv_comp); |
1768 | |
|
1769 | 0 | if (first_name[0] != '\0') { |
1770 | 0 | struct srv_info_struct *first_server = NULL; |
1771 | |
|
1772 | 0 | BINARY_ARRAY_SEARCH(servers, total, name, first_name, |
1773 | 0 | srv_name_match, first_server); |
1774 | 0 | if (first_server) { |
1775 | 0 | first = PTR_DIFF(first_server, servers) / sizeof(*servers); |
1776 | | /* |
1777 | | * The binary search may not find the exact match |
1778 | | * so we need to search backward to find the first match |
1779 | | * |
1780 | | * This implements the strange matching windows |
1781 | | * implements. (see the comment in srv_name_match(). |
1782 | | */ |
1783 | 0 | for (;first > 0;) { |
1784 | 0 | int ret; |
1785 | 0 | ret = strcasecmp_m(first_name, |
1786 | 0 | servers[first-1].name); |
1787 | 0 | if (ret > 0) { |
1788 | 0 | break; |
1789 | 0 | } |
1790 | 0 | first--; |
1791 | 0 | } |
1792 | 0 | } else { |
1793 | | /* we should return no entries */ |
1794 | 0 | first = total; |
1795 | 0 | } |
1796 | 0 | } |
1797 | |
|
1798 | 0 | { |
1799 | 0 | char *lastname=NULL; |
1800 | |
|
1801 | 0 | for (i=first;i<total;i++) { |
1802 | 0 | struct srv_info_struct *s = &servers[i]; |
1803 | |
|
1804 | 0 | if (lastname && strequal(lastname,s->name)) { |
1805 | 0 | continue; |
1806 | 0 | } |
1807 | 0 | lastname = s->name; |
1808 | 0 | data_len += fill_srv_info(s,uLevel,0,&f_len,0,&s_len,0); |
1809 | 0 | DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n", |
1810 | 0 | i, s->name, s->type, s->comment, s->domain)); |
1811 | |
|
1812 | 0 | if (data_len < buf_len) { |
1813 | 0 | counted++; |
1814 | 0 | fixed_len += f_len; |
1815 | 0 | string_len += s_len; |
1816 | 0 | } else { |
1817 | 0 | missed++; |
1818 | 0 | } |
1819 | 0 | } |
1820 | 0 | } |
1821 | |
|
1822 | 0 | *rdata_len = fixed_len + string_len; |
1823 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
1824 | 0 | if (!*rdata) { |
1825 | 0 | return False; |
1826 | 0 | } |
1827 | | |
1828 | 0 | p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ |
1829 | 0 | p = *rdata; |
1830 | 0 | f_len = fixed_len; |
1831 | 0 | s_len = string_len; |
1832 | |
|
1833 | 0 | { |
1834 | 0 | char *lastname=NULL; |
1835 | 0 | int count2 = counted; |
1836 | |
|
1837 | 0 | for (i = first; i < total && count2;i++) { |
1838 | 0 | struct srv_info_struct *s = &servers[i]; |
1839 | |
|
1840 | 0 | if (lastname && strequal(lastname,s->name)) { |
1841 | 0 | continue; |
1842 | 0 | } |
1843 | 0 | lastname = s->name; |
1844 | 0 | fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); |
1845 | 0 | DEBUG(4,("fill_srv_info[%d] %20s %8x %25s %15s\n", |
1846 | 0 | i, s->name, s->type, s->comment, s->domain)); |
1847 | 0 | count2--; |
1848 | 0 | } |
1849 | 0 | } |
1850 | |
|
1851 | 0 | *rparam_len = 8; |
1852 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1853 | 0 | if (!*rparam) { |
1854 | 0 | return False; |
1855 | 0 | } |
1856 | 0 | SSVAL(*rparam,0,(missed == 0 ? NERR_Success : ERRmoredata)); |
1857 | 0 | SSVAL(*rparam,2,0); |
1858 | 0 | SSVAL(*rparam,4,counted); |
1859 | 0 | SSVAL(*rparam,6,counted+missed); |
1860 | |
|
1861 | 0 | DEBUG(3,("NetServerEnum3 domain = %s uLevel=%d first=%d[%s => %s] counted=%d total=%d\n", |
1862 | 0 | domain,uLevel,first,first_name, |
1863 | 0 | first < total ? servers[first].name : "", |
1864 | 0 | counted,counted+missed)); |
1865 | |
|
1866 | 0 | SAFE_FREE(servers); |
1867 | |
|
1868 | 0 | return True; |
1869 | 0 | } |
1870 | | |
1871 | | /**************************************************************************** |
1872 | | command 0x34 - suspected of being a "Lookup Names" stub api |
1873 | | ****************************************************************************/ |
1874 | | |
1875 | | static bool api_RNetGroupGetUsers(struct smbd_server_connection *sconn, |
1876 | | connection_struct *conn, uint64_t vuid, |
1877 | | char *param, int tpscnt, |
1878 | | char *data, int tdscnt, |
1879 | | int mdrcnt, int mprcnt, char **rdata, |
1880 | | char **rparam, int *rdata_len, int *rparam_len) |
1881 | 0 | { |
1882 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
1883 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
1884 | 0 | char *p = skip_string(param,tpscnt,str2); |
1885 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
1886 | 0 | int buf_len = get_safe_SVAL(param,tpscnt,p,2,0); |
1887 | 0 | int counted=0; |
1888 | 0 | int missed=0; |
1889 | |
|
1890 | 0 | if (!str1 || !str2 || !p) { |
1891 | 0 | return False; |
1892 | 0 | } |
1893 | | |
1894 | 0 | DEBUG(5,("RNetGroupGetUsers: %s %s %s %d %d\n", |
1895 | 0 | str1, str2, p, uLevel, buf_len)); |
1896 | |
|
1897 | 0 | if (!prefix_ok(str1,"zWrLeh")) { |
1898 | 0 | return False; |
1899 | 0 | } |
1900 | | |
1901 | 0 | *rdata_len = 0; |
1902 | |
|
1903 | 0 | *rparam_len = 8; |
1904 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
1905 | 0 | if (!*rparam) { |
1906 | 0 | return False; |
1907 | 0 | } |
1908 | | |
1909 | 0 | SSVAL(*rparam,0,0x08AC); /* informational warning message */ |
1910 | 0 | SSVAL(*rparam,2,0); |
1911 | 0 | SSVAL(*rparam,4,counted); |
1912 | 0 | SSVAL(*rparam,6,counted+missed); |
1913 | |
|
1914 | 0 | return True; |
1915 | 0 | } |
1916 | | |
1917 | | /**************************************************************************** |
1918 | | get info about a share |
1919 | | ****************************************************************************/ |
1920 | | |
1921 | | static bool check_share_info(int uLevel, char* id) |
1922 | 0 | { |
1923 | 0 | switch( uLevel ) { |
1924 | 0 | case 0: |
1925 | 0 | if (strcmp(id,"B13") != 0) { |
1926 | 0 | return False; |
1927 | 0 | } |
1928 | 0 | break; |
1929 | 0 | case 1: |
1930 | | /* Level-2 descriptor is allowed (and ignored) */ |
1931 | 0 | if (strcmp(id,"B13BWz") != 0 && |
1932 | 0 | strcmp(id,"B13BWzWWWzB9B") != 0) { |
1933 | 0 | return False; |
1934 | 0 | } |
1935 | 0 | break; |
1936 | 0 | case 2: |
1937 | 0 | if (strcmp(id,"B13BWzWWWzB9B") != 0) { |
1938 | 0 | return False; |
1939 | 0 | } |
1940 | 0 | break; |
1941 | 0 | case 91: |
1942 | 0 | if (strcmp(id,"B13BWzWWWzB9BB9BWzWWzWW") != 0) { |
1943 | 0 | return False; |
1944 | 0 | } |
1945 | 0 | break; |
1946 | 0 | default: |
1947 | 0 | return False; |
1948 | 0 | } |
1949 | 0 | return True; |
1950 | 0 | } |
1951 | | |
1952 | | static int fill_share_info(connection_struct *conn, int snum, int uLevel, |
1953 | | char** buf, int* buflen, |
1954 | | char** stringbuf, int* stringspace, char* baseaddr) |
1955 | 0 | { |
1956 | 0 | const struct loadparm_substitution *lp_sub = |
1957 | 0 | loadparm_s3_global_substitution(); |
1958 | 0 | int struct_len; |
1959 | 0 | char* p; |
1960 | 0 | char* p2; |
1961 | 0 | int l2; |
1962 | 0 | int len; |
1963 | |
|
1964 | 0 | switch( uLevel ) { |
1965 | 0 | case 0: |
1966 | 0 | struct_len = 13; |
1967 | 0 | break; |
1968 | 0 | case 1: |
1969 | 0 | struct_len = 20; |
1970 | 0 | break; |
1971 | 0 | case 2: |
1972 | 0 | struct_len = 40; |
1973 | 0 | break; |
1974 | 0 | case 91: |
1975 | 0 | struct_len = 68; |
1976 | 0 | break; |
1977 | 0 | default: |
1978 | 0 | return -1; |
1979 | 0 | } |
1980 | | |
1981 | 0 | if (!buf) { |
1982 | 0 | len = 0; |
1983 | |
|
1984 | 0 | if (uLevel > 0) { |
1985 | 0 | len += StrlenExpanded(conn,snum,lp_comment(talloc_tos(), lp_sub, snum)); |
1986 | 0 | } |
1987 | 0 | if (uLevel > 1) { |
1988 | 0 | len += strlen(lp_path(talloc_tos(), lp_sub, snum)) + 1; |
1989 | 0 | } |
1990 | 0 | if (buflen) { |
1991 | 0 | *buflen = struct_len; |
1992 | 0 | } |
1993 | 0 | if (stringspace) { |
1994 | 0 | *stringspace = len; |
1995 | 0 | } |
1996 | 0 | return struct_len + len; |
1997 | 0 | } |
1998 | | |
1999 | 0 | len = struct_len; |
2000 | 0 | p = *buf; |
2001 | 0 | if ((*buflen) < struct_len) { |
2002 | 0 | return -1; |
2003 | 0 | } |
2004 | | |
2005 | 0 | if (stringbuf) { |
2006 | 0 | p2 = *stringbuf; |
2007 | 0 | l2 = *stringspace; |
2008 | 0 | } else { |
2009 | 0 | p2 = p + struct_len; |
2010 | 0 | l2 = (*buflen) - struct_len; |
2011 | 0 | } |
2012 | |
|
2013 | 0 | if (!baseaddr) { |
2014 | 0 | baseaddr = p; |
2015 | 0 | } |
2016 | |
|
2017 | 0 | push_ascii(p,lp_servicename(talloc_tos(), lp_sub, snum),13, STR_TERMINATE); |
2018 | |
|
2019 | 0 | if (uLevel > 0) { |
2020 | 0 | int type; |
2021 | |
|
2022 | 0 | SCVAL(p,13,0); |
2023 | 0 | type = STYPE_DISKTREE; |
2024 | 0 | if (lp_printable(snum)) { |
2025 | 0 | type = STYPE_PRINTQ; |
2026 | 0 | } |
2027 | 0 | if (strequal("IPC",lp_fstype(snum))) { |
2028 | 0 | type = STYPE_IPC; |
2029 | 0 | } |
2030 | 0 | SSVAL(p,14,type); /* device type */ |
2031 | 0 | SIVAL(p,16,PTR_DIFF(p2,baseaddr)); |
2032 | 0 | len += CopyExpanded(conn,snum,&p2,lp_comment(talloc_tos(), lp_sub, snum),&l2); |
2033 | 0 | } |
2034 | |
|
2035 | 0 | if (uLevel > 1) { |
2036 | 0 | SSVAL(p,20,ACCESS_READ|ACCESS_WRITE|ACCESS_CREATE); /* permissions */ |
2037 | 0 | SSVALS(p,22,-1); /* max uses */ |
2038 | 0 | SSVAL(p,24,1); /* current uses */ |
2039 | 0 | SIVAL(p,26,PTR_DIFF(p2,baseaddr)); /* local pathname */ |
2040 | 0 | len += CopyAndAdvance(&p2,lp_path(talloc_tos(),lp_sub, snum),&l2); |
2041 | 0 | memset(p+30,0,SHPWLEN+2); /* passwd (reserved), pad field */ |
2042 | 0 | } |
2043 | |
|
2044 | 0 | if (uLevel > 2) { |
2045 | 0 | memset(p+40,0,SHPWLEN+2); |
2046 | 0 | SSVAL(p,50,0); |
2047 | 0 | SIVAL(p,52,0); |
2048 | 0 | SSVAL(p,56,0); |
2049 | 0 | SSVAL(p,58,0); |
2050 | 0 | SIVAL(p,60,0); |
2051 | 0 | SSVAL(p,64,0); |
2052 | 0 | SSVAL(p,66,0); |
2053 | 0 | } |
2054 | |
|
2055 | 0 | if (stringbuf) { |
2056 | 0 | (*buf) = p + struct_len; |
2057 | 0 | (*buflen) -= struct_len; |
2058 | 0 | (*stringbuf) = p2; |
2059 | 0 | (*stringspace) = l2; |
2060 | 0 | } else { |
2061 | 0 | (*buf) = p2; |
2062 | 0 | (*buflen) -= len; |
2063 | 0 | } |
2064 | |
|
2065 | 0 | return len; |
2066 | 0 | } |
2067 | | |
2068 | | static bool api_RNetShareGetInfo(struct smbd_server_connection *sconn, |
2069 | | connection_struct *conn,uint64_t vuid, |
2070 | | char *param, int tpscnt, |
2071 | | char *data, int tdscnt, |
2072 | | int mdrcnt,int mprcnt, |
2073 | | char **rdata,char **rparam, |
2074 | | int *rdata_len,int *rparam_len) |
2075 | 0 | { |
2076 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2077 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2078 | 0 | char *netname_in = skip_string(param,tpscnt,str2); |
2079 | 0 | char *netname = NULL; |
2080 | 0 | char *p = skip_string(param,tpscnt,netname); |
2081 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
2082 | 0 | int snum; |
2083 | |
|
2084 | 0 | if (!str1 || !str2 || !netname_in || !p) { |
2085 | 0 | return False; |
2086 | 0 | } |
2087 | | |
2088 | 0 | snum = find_service(talloc_tos(), netname_in, &netname); |
2089 | 0 | if (snum < 0 || !netname) { |
2090 | 0 | return False; |
2091 | 0 | } |
2092 | | |
2093 | | /* check it's a supported variant */ |
2094 | 0 | if (!prefix_ok(str1,"zWrLh")) { |
2095 | 0 | return False; |
2096 | 0 | } |
2097 | 0 | if (!check_share_info(uLevel,str2)) { |
2098 | 0 | return False; |
2099 | 0 | } |
2100 | | |
2101 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
2102 | 0 | if (!*rdata) { |
2103 | 0 | return False; |
2104 | 0 | } |
2105 | 0 | p = *rdata; |
2106 | 0 | *rdata_len = fill_share_info(conn,snum,uLevel,&p,&mdrcnt,0,0,0); |
2107 | 0 | if (*rdata_len < 0) { |
2108 | 0 | return False; |
2109 | 0 | } |
2110 | | |
2111 | 0 | *rparam_len = 6; |
2112 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2113 | 0 | if (!*rparam) { |
2114 | 0 | return False; |
2115 | 0 | } |
2116 | 0 | SSVAL(*rparam,0,NERR_Success); |
2117 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
2118 | 0 | SSVAL(*rparam,4,*rdata_len); |
2119 | |
|
2120 | 0 | return True; |
2121 | 0 | } |
2122 | | |
2123 | | /**************************************************************************** |
2124 | | View the list of available shares. |
2125 | | |
2126 | | This function is the server side of the NetShareEnum() RAP call. |
2127 | | It fills the return buffer with share names and share comments. |
2128 | | Note that the return buffer normally (in all known cases) allows only |
2129 | | twelve byte strings for share names (plus one for a nul terminator). |
2130 | | Share names longer than 12 bytes must be skipped. |
2131 | | ****************************************************************************/ |
2132 | | |
2133 | | static bool api_RNetShareEnum(struct smbd_server_connection *sconn, |
2134 | | connection_struct *conn, uint64_t vuid, |
2135 | | char *param, int tpscnt, |
2136 | | char *data, int tdscnt, |
2137 | | int mdrcnt, |
2138 | | int mprcnt, |
2139 | | char **rdata, |
2140 | | char **rparam, |
2141 | | int *rdata_len, |
2142 | | int *rparam_len ) |
2143 | 0 | { |
2144 | 0 | const struct loadparm_substitution *lp_sub = |
2145 | 0 | loadparm_s3_global_substitution(); |
2146 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2147 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2148 | 0 | char *p = skip_string(param,tpscnt,str2); |
2149 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
2150 | 0 | int buf_len = get_safe_SVAL(param,tpscnt,p,2,0); |
2151 | 0 | char *p2; |
2152 | 0 | int count = 0; |
2153 | 0 | int total=0,counted=0; |
2154 | 0 | bool missed = False; |
2155 | 0 | int i; |
2156 | 0 | int data_len, fixed_len, string_len; |
2157 | 0 | int f_len = 0, s_len = 0; |
2158 | |
|
2159 | 0 | if (!str1 || !str2 || !p) { |
2160 | 0 | return False; |
2161 | 0 | } |
2162 | | |
2163 | 0 | if (!prefix_ok(str1,"WrLeh")) { |
2164 | 0 | return False; |
2165 | 0 | } |
2166 | 0 | if (!check_share_info(uLevel,str2)) { |
2167 | 0 | return False; |
2168 | 0 | } |
2169 | | |
2170 | | /* Ensure all the usershares are loaded. */ |
2171 | 0 | become_root(); |
2172 | 0 | delete_and_reload_printers(); |
2173 | 0 | load_registry_shares(); |
2174 | 0 | count = load_usershare_shares(NULL, connections_snum_used); |
2175 | 0 | unbecome_root(); |
2176 | |
|
2177 | 0 | data_len = fixed_len = string_len = 0; |
2178 | 0 | for (i=0;i<count;i++) { |
2179 | 0 | fstring servicename_dos; |
2180 | 0 | if (!(lp_browseable(i) && lp_snum_ok(i))) { |
2181 | 0 | continue; |
2182 | 0 | } |
2183 | 0 | push_ascii_fstring(servicename_dos, lp_servicename(talloc_tos(), lp_sub, i)); |
2184 | | /* Maximum name length = 13. */ |
2185 | 0 | if( lp_browseable( i ) && lp_snum_ok( i ) && (strlen(servicename_dos) < 13)) { |
2186 | 0 | total++; |
2187 | 0 | data_len += fill_share_info(conn,i,uLevel,0,&f_len,0,&s_len,0); |
2188 | 0 | if (data_len < buf_len) { |
2189 | 0 | counted++; |
2190 | 0 | fixed_len += f_len; |
2191 | 0 | string_len += s_len; |
2192 | 0 | } else { |
2193 | 0 | missed = True; |
2194 | 0 | } |
2195 | 0 | } |
2196 | 0 | } |
2197 | |
|
2198 | 0 | *rdata_len = fixed_len + string_len; |
2199 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
2200 | 0 | if (!*rdata) { |
2201 | 0 | return False; |
2202 | 0 | } |
2203 | | |
2204 | 0 | p2 = (*rdata) + fixed_len; /* auxiliary data (strings) will go here */ |
2205 | 0 | p = *rdata; |
2206 | 0 | f_len = fixed_len; |
2207 | 0 | s_len = string_len; |
2208 | |
|
2209 | 0 | for( i = 0; i < count; i++ ) { |
2210 | 0 | fstring servicename_dos; |
2211 | 0 | if (!(lp_browseable(i) && lp_snum_ok(i))) { |
2212 | 0 | continue; |
2213 | 0 | } |
2214 | | |
2215 | 0 | push_ascii_fstring(servicename_dos, |
2216 | 0 | lp_servicename(talloc_tos(), lp_sub, i)); |
2217 | 0 | if (lp_browseable(i) && lp_snum_ok(i) && (strlen(servicename_dos) < 13)) { |
2218 | 0 | if (fill_share_info( conn,i,uLevel,&p,&f_len,&p2,&s_len,*rdata ) < 0) { |
2219 | 0 | break; |
2220 | 0 | } |
2221 | 0 | } |
2222 | 0 | } |
2223 | |
|
2224 | 0 | *rparam_len = 8; |
2225 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2226 | 0 | if (!*rparam) { |
2227 | 0 | return False; |
2228 | 0 | } |
2229 | 0 | SSVAL(*rparam,0,missed ? ERRmoredata : NERR_Success); |
2230 | 0 | SSVAL(*rparam,2,0); |
2231 | 0 | SSVAL(*rparam,4,counted); |
2232 | 0 | SSVAL(*rparam,6,total); |
2233 | |
|
2234 | 0 | DEBUG(3,("RNetShareEnum gave %d entries of %d (%d %d %d %d)\n", |
2235 | 0 | counted,total,uLevel, |
2236 | 0 | buf_len,*rdata_len,mdrcnt)); |
2237 | |
|
2238 | 0 | return True; |
2239 | 0 | } |
2240 | | |
2241 | | /**************************************************************************** |
2242 | | Add a share |
2243 | | ****************************************************************************/ |
2244 | | |
2245 | | static bool api_RNetShareAdd(struct smbd_server_connection *sconn, |
2246 | | connection_struct *conn,uint64_t vuid, |
2247 | | char *param, int tpscnt, |
2248 | | char *data, int tdscnt, |
2249 | | int mdrcnt,int mprcnt, |
2250 | | char **rdata,char **rparam, |
2251 | | int *rdata_len,int *rparam_len) |
2252 | 0 | { |
2253 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2254 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2255 | 0 | char *p = skip_string(param,tpscnt,str2); |
2256 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
2257 | 0 | fstring sharename; |
2258 | 0 | fstring comment; |
2259 | 0 | char *pathname = NULL; |
2260 | 0 | unsigned int offset; |
2261 | 0 | int res = ERRunsup; |
2262 | 0 | size_t converted_size; |
2263 | |
|
2264 | 0 | WERROR werr = WERR_OK; |
2265 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
2266 | 0 | NTSTATUS status; |
2267 | 0 | struct rpc_pipe_client *cli = NULL; |
2268 | 0 | union srvsvc_NetShareInfo info; |
2269 | 0 | struct srvsvc_NetShareInfo2 info2; |
2270 | 0 | struct dcerpc_binding_handle *b; |
2271 | |
|
2272 | 0 | if (!str1 || !str2 || !p) { |
2273 | 0 | return False; |
2274 | 0 | } |
2275 | | |
2276 | | /* check it's a supported variant */ |
2277 | 0 | if (!prefix_ok(str1,RAP_WShareAdd_REQ)) { |
2278 | 0 | return False; |
2279 | 0 | } |
2280 | 0 | if (!check_share_info(uLevel,str2)) { |
2281 | 0 | return False; |
2282 | 0 | } |
2283 | 0 | if (uLevel != 2) { |
2284 | 0 | return False; |
2285 | 0 | } |
2286 | | |
2287 | | /* Do we have a string ? */ |
2288 | 0 | if (skip_string(data,mdrcnt,data) == NULL) { |
2289 | 0 | return False; |
2290 | 0 | } |
2291 | 0 | pull_ascii_fstring(sharename,data); |
2292 | |
|
2293 | 0 | if (mdrcnt < 28) { |
2294 | 0 | return False; |
2295 | 0 | } |
2296 | | |
2297 | | /* only support disk share adds */ |
2298 | 0 | if (SVAL(data,14)!=STYPE_DISKTREE) { |
2299 | 0 | return False; |
2300 | 0 | } |
2301 | | |
2302 | 0 | offset = IVAL(data, 16); |
2303 | 0 | if (offset >= mdrcnt) { |
2304 | 0 | res = ERRinvalidparam; |
2305 | 0 | goto out; |
2306 | 0 | } |
2307 | | |
2308 | | /* Do we have a string ? */ |
2309 | 0 | if (skip_string(data,mdrcnt,data+offset) == NULL) { |
2310 | 0 | return False; |
2311 | 0 | } |
2312 | 0 | pull_ascii_fstring(comment, offset? (data+offset) : ""); |
2313 | |
|
2314 | 0 | offset = IVAL(data, 26); |
2315 | |
|
2316 | 0 | if (offset >= mdrcnt) { |
2317 | 0 | res = ERRinvalidparam; |
2318 | 0 | goto out; |
2319 | 0 | } |
2320 | | |
2321 | | /* Do we have a string ? */ |
2322 | 0 | if (skip_string(data,mdrcnt,data+offset) == NULL) { |
2323 | 0 | return False; |
2324 | 0 | } |
2325 | | |
2326 | 0 | if (!pull_ascii_talloc(talloc_tos(), &pathname, |
2327 | 0 | offset ? (data+offset) : "", &converted_size)) |
2328 | 0 | { |
2329 | 0 | DEBUG(0,("api_RNetShareAdd: pull_ascii_talloc failed: %s\n", |
2330 | 0 | strerror(errno))); |
2331 | 0 | } |
2332 | |
|
2333 | 0 | if (!pathname) { |
2334 | 0 | return false; |
2335 | 0 | } |
2336 | | |
2337 | 0 | status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc, |
2338 | 0 | conn->session_info, |
2339 | 0 | conn->sconn->remote_address, |
2340 | 0 | conn->sconn->local_address, |
2341 | 0 | conn->sconn->msg_ctx, |
2342 | 0 | &cli); |
2343 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2344 | 0 | DEBUG(0,("api_RNetShareAdd: could not connect to srvsvc: %s\n", |
2345 | 0 | nt_errstr(status))); |
2346 | 0 | res = W_ERROR_V(ntstatus_to_werror(status)); |
2347 | 0 | goto out; |
2348 | 0 | } |
2349 | | |
2350 | 0 | b = cli->binding_handle; |
2351 | |
|
2352 | 0 | info2.name = sharename; |
2353 | 0 | info2.type = STYPE_DISKTREE; |
2354 | 0 | info2.comment = comment; |
2355 | 0 | info2.permissions = 0; |
2356 | 0 | info2.max_users = 0; |
2357 | 0 | info2.current_users = 0; |
2358 | 0 | info2.path = pathname; |
2359 | 0 | info2.password = NULL; |
2360 | |
|
2361 | 0 | info.info2 = &info2; |
2362 | |
|
2363 | 0 | status = dcerpc_srvsvc_NetShareAdd(b, mem_ctx, |
2364 | 0 | cli->srv_name_slash, |
2365 | 0 | 2, |
2366 | 0 | &info, |
2367 | 0 | NULL, |
2368 | 0 | &werr); |
2369 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2370 | 0 | res = W_ERROR_V(ntstatus_to_werror(status)); |
2371 | 0 | goto out; |
2372 | 0 | } |
2373 | 0 | if (!W_ERROR_IS_OK(werr)) { |
2374 | 0 | res = W_ERROR_V(werr); |
2375 | 0 | goto out; |
2376 | 0 | } |
2377 | | |
2378 | 0 | *rparam_len = 6; |
2379 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2380 | 0 | if (!*rparam) { |
2381 | 0 | return False; |
2382 | 0 | } |
2383 | 0 | SSVAL(*rparam,0,NERR_Success); |
2384 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
2385 | 0 | SSVAL(*rparam,4,*rdata_len); |
2386 | 0 | *rdata_len = 0; |
2387 | |
|
2388 | 0 | return True; |
2389 | | |
2390 | 0 | out: |
2391 | |
|
2392 | 0 | *rparam_len = 4; |
2393 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2394 | 0 | if (!*rparam) { |
2395 | 0 | return False; |
2396 | 0 | } |
2397 | 0 | *rdata_len = 0; |
2398 | 0 | SSVAL(*rparam,0,res); |
2399 | 0 | SSVAL(*rparam,2,0); |
2400 | 0 | return True; |
2401 | 0 | } |
2402 | | |
2403 | | /**************************************************************************** |
2404 | | view list of groups available |
2405 | | ****************************************************************************/ |
2406 | | |
2407 | | static bool api_RNetGroupEnum(struct smbd_server_connection *sconn, |
2408 | | connection_struct *conn,uint64_t vuid, |
2409 | | char *param, int tpscnt, |
2410 | | char *data, int tdscnt, |
2411 | | int mdrcnt,int mprcnt, |
2412 | | char **rdata,char **rparam, |
2413 | | int *rdata_len,int *rparam_len) |
2414 | 0 | { |
2415 | 0 | int i; |
2416 | 0 | int errflags=0; |
2417 | 0 | int resume_context, cli_buf_size; |
2418 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2419 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2420 | 0 | char *p = skip_string(param,tpscnt,str2); |
2421 | |
|
2422 | 0 | uint32_t num_groups; |
2423 | 0 | uint32_t resume_handle; |
2424 | 0 | struct rpc_pipe_client *samr_pipe = NULL; |
2425 | 0 | struct policy_handle samr_handle, domain_handle; |
2426 | 0 | NTSTATUS status, result; |
2427 | 0 | struct dcerpc_binding_handle *b; |
2428 | |
|
2429 | 0 | if (!str1 || !str2 || !p) { |
2430 | 0 | return False; |
2431 | 0 | } |
2432 | | |
2433 | 0 | if (strcmp(str1,"WrLeh") != 0) { |
2434 | 0 | return False; |
2435 | 0 | } |
2436 | | |
2437 | | /* parameters |
2438 | | * W-> resume context (number of users to skip) |
2439 | | * r -> return parameter pointer to receive buffer |
2440 | | * L -> length of receive buffer |
2441 | | * e -> return parameter number of entries |
2442 | | * h -> return parameter total number of users |
2443 | | */ |
2444 | | |
2445 | 0 | if (strcmp("B21",str2) != 0) { |
2446 | 0 | return False; |
2447 | 0 | } |
2448 | | |
2449 | 0 | status = rpc_pipe_open_interface( |
2450 | 0 | talloc_tos(), &ndr_table_samr, |
2451 | 0 | conn->session_info, conn->sconn->remote_address, |
2452 | 0 | conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe); |
2453 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2454 | 0 | DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n", |
2455 | 0 | nt_errstr(status))); |
2456 | 0 | return false; |
2457 | 0 | } |
2458 | | |
2459 | 0 | b = samr_pipe->binding_handle; |
2460 | |
|
2461 | 0 | status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(), |
2462 | 0 | SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle, |
2463 | 0 | &result); |
2464 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2465 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2466 | 0 | nt_errstr(status))); |
2467 | 0 | return false; |
2468 | 0 | } |
2469 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2470 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2471 | 0 | nt_errstr(result))); |
2472 | 0 | return false; |
2473 | 0 | } |
2474 | | |
2475 | 0 | status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle, |
2476 | 0 | SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, |
2477 | 0 | get_global_sam_sid(), &domain_handle, |
2478 | 0 | &result); |
2479 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2480 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2481 | 0 | nt_errstr(status))); |
2482 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2483 | 0 | return false; |
2484 | 0 | } |
2485 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2486 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2487 | 0 | nt_errstr(result))); |
2488 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2489 | 0 | return false; |
2490 | 0 | } |
2491 | | |
2492 | 0 | resume_context = get_safe_SVAL(param,tpscnt,p,0,-1); |
2493 | 0 | cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0); |
2494 | 0 | DEBUG(10,("api_RNetGroupEnum:resume context: %d, client buffer size: " |
2495 | 0 | "%d\n", resume_context, cli_buf_size)); |
2496 | |
|
2497 | 0 | *rdata_len = cli_buf_size; |
2498 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
2499 | 0 | if (!*rdata) { |
2500 | 0 | return False; |
2501 | 0 | } |
2502 | | |
2503 | 0 | p = *rdata; |
2504 | |
|
2505 | 0 | errflags = NERR_Success; |
2506 | 0 | num_groups = 0; |
2507 | 0 | resume_handle = 0; |
2508 | |
|
2509 | 0 | while (true) { |
2510 | 0 | struct samr_SamArray *sam_entries; |
2511 | 0 | uint32_t num_entries; |
2512 | |
|
2513 | 0 | status = dcerpc_samr_EnumDomainGroups(b, talloc_tos(), |
2514 | 0 | &domain_handle, |
2515 | 0 | &resume_handle, |
2516 | 0 | &sam_entries, 1, |
2517 | 0 | &num_entries, |
2518 | 0 | &result); |
2519 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2520 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned " |
2521 | 0 | "%s\n", nt_errstr(status))); |
2522 | 0 | break; |
2523 | 0 | } |
2524 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2525 | 0 | status = result; |
2526 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned " |
2527 | 0 | "%s\n", nt_errstr(result))); |
2528 | 0 | break; |
2529 | 0 | } |
2530 | | |
2531 | 0 | if (num_entries == 0) { |
2532 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainGroups returned " |
2533 | 0 | "no entries -- done\n")); |
2534 | 0 | break; |
2535 | 0 | } |
2536 | | |
2537 | 0 | for(i=0; i<num_entries; i++) { |
2538 | 0 | const char *name; |
2539 | |
|
2540 | 0 | name = sam_entries->entries[i].name.string; |
2541 | |
|
2542 | 0 | if( ((PTR_DIFF(p,*rdata)+21) > *rdata_len) ) { |
2543 | | /* set overflow error */ |
2544 | 0 | DEBUG(3,("overflow on entry %d group %s\n", i, |
2545 | 0 | name)); |
2546 | 0 | errflags=234; |
2547 | 0 | break; |
2548 | 0 | } |
2549 | | |
2550 | | /* truncate the name at 21 chars. */ |
2551 | 0 | memset(p, 0, 21); |
2552 | 0 | strlcpy(p, name, 21); |
2553 | 0 | DEBUG(10,("adding entry %d group %s\n", i, p)); |
2554 | 0 | p += 21; |
2555 | 0 | p += 5; /* Both NT4 and W2k3SP1 do padding here. No |
2556 | | * idea why... */ |
2557 | 0 | num_groups += 1; |
2558 | 0 | } |
2559 | |
|
2560 | 0 | if (errflags != NERR_Success) { |
2561 | 0 | break; |
2562 | 0 | } |
2563 | | |
2564 | 0 | TALLOC_FREE(sam_entries); |
2565 | 0 | } |
2566 | |
|
2567 | 0 | dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result); |
2568 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2569 | |
|
2570 | 0 | *rdata_len = PTR_DIFF(p,*rdata); |
2571 | |
|
2572 | 0 | *rparam_len = 8; |
2573 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2574 | 0 | if (!*rparam) { |
2575 | 0 | return False; |
2576 | 0 | } |
2577 | 0 | SSVAL(*rparam, 0, errflags); |
2578 | 0 | SSVAL(*rparam, 2, 0); /* converter word */ |
2579 | 0 | SSVAL(*rparam, 4, num_groups); /* is this right?? */ |
2580 | 0 | SSVAL(*rparam, 6, resume_context+num_groups); /* is this right?? */ |
2581 | |
|
2582 | 0 | return(True); |
2583 | 0 | } |
2584 | | |
2585 | | /******************************************************************* |
2586 | | Get groups that a user is a member of. |
2587 | | ******************************************************************/ |
2588 | | |
2589 | | static bool api_NetUserGetGroups(struct smbd_server_connection *sconn, |
2590 | | connection_struct *conn,uint64_t vuid, |
2591 | | char *param, int tpscnt, |
2592 | | char *data, int tdscnt, |
2593 | | int mdrcnt,int mprcnt, |
2594 | | char **rdata,char **rparam, |
2595 | | int *rdata_len,int *rparam_len) |
2596 | 0 | { |
2597 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2598 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2599 | 0 | char *UserName = skip_string(param,tpscnt,str2); |
2600 | 0 | char *p = skip_string(param,tpscnt,UserName); |
2601 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
2602 | 0 | const char *level_string; |
2603 | 0 | int count=0; |
2604 | 0 | bool ret = False; |
2605 | 0 | uint32_t i; |
2606 | 0 | char *endp = NULL; |
2607 | |
|
2608 | 0 | struct rpc_pipe_client *samr_pipe = NULL; |
2609 | 0 | struct policy_handle samr_handle, domain_handle, user_handle; |
2610 | 0 | struct lsa_String name; |
2611 | 0 | struct lsa_Strings names; |
2612 | 0 | struct samr_Ids type, rid; |
2613 | 0 | struct samr_RidWithAttributeArray *rids; |
2614 | 0 | NTSTATUS status, result; |
2615 | 0 | struct dcerpc_binding_handle *b; |
2616 | |
|
2617 | 0 | if (!str1 || !str2 || !UserName || !p) { |
2618 | 0 | return False; |
2619 | 0 | } |
2620 | | |
2621 | 0 | *rparam_len = 8; |
2622 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2623 | 0 | if (!*rparam) { |
2624 | 0 | return False; |
2625 | 0 | } |
2626 | | |
2627 | | /* check it's a supported variant */ |
2628 | | |
2629 | 0 | if ( strcmp(str1,"zWrLeh") != 0 ) |
2630 | 0 | return False; |
2631 | | |
2632 | 0 | switch( uLevel ) { |
2633 | 0 | case 0: |
2634 | 0 | level_string = "B21"; |
2635 | 0 | break; |
2636 | 0 | default: |
2637 | 0 | return False; |
2638 | 0 | } |
2639 | | |
2640 | 0 | if (strcmp(level_string,str2) != 0) |
2641 | 0 | return False; |
2642 | | |
2643 | 0 | *rdata_len = mdrcnt + 1024; |
2644 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
2645 | 0 | if (!*rdata) { |
2646 | 0 | return False; |
2647 | 0 | } |
2648 | | |
2649 | 0 | SSVAL(*rparam,0,NERR_Success); |
2650 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
2651 | |
|
2652 | 0 | p = *rdata; |
2653 | 0 | endp = *rdata + *rdata_len; |
2654 | |
|
2655 | 0 | status = rpc_pipe_open_interface( |
2656 | 0 | talloc_tos(), &ndr_table_samr, |
2657 | 0 | conn->session_info, conn->sconn->remote_address, |
2658 | 0 | conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe); |
2659 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2660 | 0 | DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n", |
2661 | 0 | nt_errstr(status))); |
2662 | 0 | return false; |
2663 | 0 | } |
2664 | | |
2665 | 0 | b = samr_pipe->binding_handle; |
2666 | |
|
2667 | 0 | status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(), |
2668 | 0 | SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle, |
2669 | 0 | &result); |
2670 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2671 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2672 | 0 | nt_errstr(status))); |
2673 | 0 | return false; |
2674 | 0 | } |
2675 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2676 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2677 | 0 | nt_errstr(result))); |
2678 | 0 | return false; |
2679 | 0 | } |
2680 | | |
2681 | 0 | status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle, |
2682 | 0 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, |
2683 | 0 | get_global_sam_sid(), &domain_handle, |
2684 | 0 | &result); |
2685 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2686 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2687 | 0 | nt_errstr(status))); |
2688 | 0 | goto close_sam; |
2689 | 0 | } |
2690 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2691 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2692 | 0 | nt_errstr(result))); |
2693 | 0 | goto close_sam; |
2694 | 0 | } |
2695 | | |
2696 | 0 | name.string = UserName; |
2697 | |
|
2698 | 0 | status = dcerpc_samr_LookupNames(b, talloc_tos(), |
2699 | 0 | &domain_handle, 1, &name, |
2700 | 0 | &rid, &type, |
2701 | 0 | &result); |
2702 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2703 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2704 | 0 | nt_errstr(status))); |
2705 | 0 | goto close_domain; |
2706 | 0 | } |
2707 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2708 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2709 | 0 | nt_errstr(result))); |
2710 | 0 | goto close_domain; |
2711 | 0 | } |
2712 | 0 | if (rid.count != 1) { |
2713 | 0 | status = NT_STATUS_INVALID_NETWORK_RESPONSE; |
2714 | 0 | goto close_domain; |
2715 | 0 | } |
2716 | 0 | if (type.count != 1) { |
2717 | 0 | status = NT_STATUS_INVALID_NETWORK_RESPONSE; |
2718 | 0 | goto close_domain; |
2719 | 0 | } |
2720 | | |
2721 | 0 | if (type.ids[0] != SID_NAME_USER) { |
2722 | 0 | DEBUG(10, ("%s is a %s, not a user\n", UserName, |
2723 | 0 | sid_type_lookup(type.ids[0]))); |
2724 | 0 | goto close_domain; |
2725 | 0 | } |
2726 | | |
2727 | 0 | status = dcerpc_samr_OpenUser(b, talloc_tos(), |
2728 | 0 | &domain_handle, |
2729 | 0 | SAMR_USER_ACCESS_GET_GROUPS, |
2730 | 0 | rid.ids[0], &user_handle, |
2731 | 0 | &result); |
2732 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2733 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2734 | 0 | nt_errstr(status))); |
2735 | 0 | goto close_domain; |
2736 | 0 | } |
2737 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2738 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2739 | 0 | nt_errstr(result))); |
2740 | 0 | goto close_domain; |
2741 | 0 | } |
2742 | | |
2743 | 0 | status = dcerpc_samr_GetGroupsForUser(b, talloc_tos(), |
2744 | 0 | &user_handle, &rids, |
2745 | 0 | &result); |
2746 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2747 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2748 | 0 | nt_errstr(status))); |
2749 | 0 | goto close_user; |
2750 | 0 | } |
2751 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2752 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_LookupNames failed: %s\n", |
2753 | 0 | nt_errstr(result))); |
2754 | 0 | goto close_user; |
2755 | 0 | } |
2756 | | |
2757 | 0 | for (i=0; i<rids->count; i++) { |
2758 | |
|
2759 | 0 | status = dcerpc_samr_LookupRids(b, talloc_tos(), |
2760 | 0 | &domain_handle, |
2761 | 0 | 1, &rids->rids[i].rid, |
2762 | 0 | &names, &type, |
2763 | 0 | &result); |
2764 | 0 | if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result) && (names.count == 1)) { |
2765 | 0 | strlcpy(p, names.names[0].string, PTR_DIFF(endp,p)); |
2766 | 0 | p += 21; |
2767 | 0 | count++; |
2768 | 0 | } |
2769 | 0 | } |
2770 | |
|
2771 | 0 | *rdata_len = PTR_DIFF(p,*rdata); |
2772 | |
|
2773 | 0 | SSVAL(*rparam,4,count); /* is this right?? */ |
2774 | 0 | SSVAL(*rparam,6,count); /* is this right?? */ |
2775 | |
|
2776 | 0 | ret = True; |
2777 | |
|
2778 | 0 | close_user: |
2779 | 0 | dcerpc_samr_Close(b, talloc_tos(), &user_handle, &result); |
2780 | 0 | close_domain: |
2781 | 0 | dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result); |
2782 | 0 | close_sam: |
2783 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2784 | |
|
2785 | 0 | return ret; |
2786 | 0 | } |
2787 | | |
2788 | | /******************************************************************* |
2789 | | Get all users. |
2790 | | ******************************************************************/ |
2791 | | |
2792 | | static bool api_RNetUserEnum(struct smbd_server_connection *sconn, |
2793 | | connection_struct *conn, uint64_t vuid, |
2794 | | char *param, int tpscnt, |
2795 | | char *data, int tdscnt, |
2796 | | int mdrcnt,int mprcnt, |
2797 | | char **rdata,char **rparam, |
2798 | | int *rdata_len,int *rparam_len) |
2799 | 0 | { |
2800 | 0 | int count_sent=0; |
2801 | 0 | int num_users=0; |
2802 | 0 | int errflags=0; |
2803 | 0 | int i, resume_context, cli_buf_size; |
2804 | 0 | uint32_t resume_handle; |
2805 | |
|
2806 | 0 | struct rpc_pipe_client *samr_pipe = NULL; |
2807 | 0 | struct policy_handle samr_handle, domain_handle; |
2808 | 0 | NTSTATUS status, result; |
2809 | |
|
2810 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
2811 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
2812 | 0 | char *p = skip_string(param,tpscnt,str2); |
2813 | 0 | char *endp = NULL; |
2814 | |
|
2815 | 0 | struct dcerpc_binding_handle *b; |
2816 | |
|
2817 | 0 | if (!str1 || !str2 || !p) { |
2818 | 0 | return False; |
2819 | 0 | } |
2820 | | |
2821 | 0 | if (strcmp(str1,"WrLeh") != 0) |
2822 | 0 | return False; |
2823 | | /* parameters |
2824 | | * W-> resume context (number of users to skip) |
2825 | | * r -> return parameter pointer to receive buffer |
2826 | | * L -> length of receive buffer |
2827 | | * e -> return parameter number of entries |
2828 | | * h -> return parameter total number of users |
2829 | | */ |
2830 | | |
2831 | 0 | resume_context = get_safe_SVAL(param,tpscnt,p,0,-1); |
2832 | 0 | cli_buf_size= get_safe_SVAL(param,tpscnt,p,2,0); |
2833 | 0 | DEBUG(10,("api_RNetUserEnum:resume context: %d, client buffer size: %d\n", |
2834 | 0 | resume_context, cli_buf_size)); |
2835 | |
|
2836 | 0 | *rparam_len = 8; |
2837 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2838 | 0 | if (!*rparam) { |
2839 | 0 | return False; |
2840 | 0 | } |
2841 | | |
2842 | | /* check it's a supported variant */ |
2843 | 0 | if (strcmp("B21",str2) != 0) |
2844 | 0 | return False; |
2845 | | |
2846 | 0 | *rdata_len = cli_buf_size; |
2847 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
2848 | 0 | if (!*rdata) { |
2849 | 0 | return False; |
2850 | 0 | } |
2851 | | |
2852 | 0 | p = *rdata; |
2853 | 0 | endp = *rdata + *rdata_len; |
2854 | |
|
2855 | 0 | status = rpc_pipe_open_interface( |
2856 | 0 | talloc_tos(), &ndr_table_samr, |
2857 | 0 | conn->session_info, conn->sconn->remote_address, |
2858 | 0 | conn->sconn->local_address, conn->sconn->msg_ctx, &samr_pipe); |
2859 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2860 | 0 | DEBUG(0, ("api_RNetUserEnum: Could not connect to samr: %s\n", |
2861 | 0 | nt_errstr(status))); |
2862 | 0 | return false; |
2863 | 0 | } |
2864 | | |
2865 | 0 | b = samr_pipe->binding_handle; |
2866 | |
|
2867 | 0 | status = dcerpc_samr_Connect2(b, talloc_tos(), lp_netbios_name(), |
2868 | 0 | SAMR_ACCESS_LOOKUP_DOMAIN, &samr_handle, |
2869 | 0 | &result); |
2870 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2871 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2872 | 0 | nt_errstr(status))); |
2873 | 0 | return false; |
2874 | 0 | } |
2875 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2876 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_Connect2 failed: %s\n", |
2877 | 0 | nt_errstr(result))); |
2878 | 0 | return false; |
2879 | 0 | } |
2880 | | |
2881 | 0 | status = dcerpc_samr_OpenDomain(b, talloc_tos(), &samr_handle, |
2882 | 0 | SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS, |
2883 | 0 | get_global_sam_sid(), &domain_handle, |
2884 | 0 | &result); |
2885 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2886 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2887 | 0 | nt_errstr(status))); |
2888 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2889 | 0 | return false; |
2890 | 0 | } |
2891 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2892 | 0 | DEBUG(0, ("api_RNetUserEnum: samr_OpenDomain failed: %s\n", |
2893 | 0 | nt_errstr(result))); |
2894 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2895 | 0 | return false; |
2896 | 0 | } |
2897 | | |
2898 | 0 | errflags=NERR_Success; |
2899 | |
|
2900 | 0 | resume_handle = 0; |
2901 | |
|
2902 | 0 | while (true) { |
2903 | 0 | struct samr_SamArray *sam_entries; |
2904 | 0 | uint32_t num_entries; |
2905 | |
|
2906 | 0 | status = dcerpc_samr_EnumDomainUsers(b, talloc_tos(), |
2907 | 0 | &domain_handle, |
2908 | 0 | &resume_handle, |
2909 | 0 | 0, &sam_entries, 1, |
2910 | 0 | &num_entries, |
2911 | 0 | &result); |
2912 | |
|
2913 | 0 | if (!NT_STATUS_IS_OK(status)) { |
2914 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned " |
2915 | 0 | "%s\n", nt_errstr(status))); |
2916 | 0 | break; |
2917 | 0 | } |
2918 | 0 | if (!NT_STATUS_IS_OK(result)) { |
2919 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned " |
2920 | 0 | "%s\n", nt_errstr(result))); |
2921 | 0 | break; |
2922 | 0 | } |
2923 | | |
2924 | 0 | if (num_entries == 0) { |
2925 | 0 | DEBUG(10, ("dcerpc_samr_EnumDomainUsers returned " |
2926 | 0 | "no entries -- done\n")); |
2927 | 0 | break; |
2928 | 0 | } |
2929 | | |
2930 | 0 | for (i=0; i<num_entries; i++) { |
2931 | 0 | const char *name; |
2932 | |
|
2933 | 0 | name = sam_entries->entries[i].name.string; |
2934 | |
|
2935 | 0 | if(((PTR_DIFF(p,*rdata)+21)<=*rdata_len) |
2936 | 0 | &&(strlen(name)<=21)) { |
2937 | 0 | strlcpy(p,name,PTR_DIFF(endp,p)); |
2938 | 0 | DEBUG(10,("api_RNetUserEnum:adding entry %d " |
2939 | 0 | "username %s\n",count_sent,p)); |
2940 | 0 | p += 21; |
2941 | 0 | count_sent++; |
2942 | 0 | } else { |
2943 | | /* set overflow error */ |
2944 | 0 | DEBUG(10,("api_RNetUserEnum:overflow on entry %d " |
2945 | 0 | "username %s\n",count_sent,name)); |
2946 | 0 | errflags=234; |
2947 | 0 | break; |
2948 | 0 | } |
2949 | 0 | } |
2950 | |
|
2951 | 0 | if (errflags != NERR_Success) { |
2952 | 0 | break; |
2953 | 0 | } |
2954 | | |
2955 | 0 | TALLOC_FREE(sam_entries); |
2956 | 0 | } |
2957 | |
|
2958 | 0 | dcerpc_samr_Close(b, talloc_tos(), &domain_handle, &result); |
2959 | 0 | dcerpc_samr_Close(b, talloc_tos(), &samr_handle, &result); |
2960 | |
|
2961 | 0 | *rdata_len = PTR_DIFF(p,*rdata); |
2962 | |
|
2963 | 0 | SSVAL(*rparam,0,errflags); |
2964 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
2965 | 0 | SSVAL(*rparam,4,count_sent); /* is this right?? */ |
2966 | 0 | SSVAL(*rparam,6,num_users); /* is this right?? */ |
2967 | |
|
2968 | 0 | return True; |
2969 | 0 | } |
2970 | | |
2971 | | /**************************************************************************** |
2972 | | Get the time of day info. |
2973 | | ****************************************************************************/ |
2974 | | |
2975 | | static bool api_NetRemoteTOD(struct smbd_server_connection *sconn, |
2976 | | connection_struct *conn,uint64_t vuid, |
2977 | | char *param, int tpscnt, |
2978 | | char *data, int tdscnt, |
2979 | | int mdrcnt,int mprcnt, |
2980 | | char **rdata,char **rparam, |
2981 | | int *rdata_len,int *rparam_len) |
2982 | 0 | { |
2983 | 0 | struct tm *t; |
2984 | 0 | time_t unixdate = time(NULL); |
2985 | 0 | char *p; |
2986 | |
|
2987 | 0 | *rparam_len = 4; |
2988 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
2989 | 0 | if (!*rparam) { |
2990 | 0 | return False; |
2991 | 0 | } |
2992 | | |
2993 | 0 | *rdata_len = 21; |
2994 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
2995 | 0 | if (!*rdata) { |
2996 | 0 | return False; |
2997 | 0 | } |
2998 | | |
2999 | 0 | SSVAL(*rparam,0,NERR_Success); |
3000 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3001 | |
|
3002 | 0 | p = *rdata; |
3003 | |
|
3004 | 0 | srv_put_dos_date3(p,0,unixdate); /* this is the time that is looked at |
3005 | | by NT in a "net time" operation, |
3006 | | it seems to ignore the one below */ |
3007 | | |
3008 | | /* the client expects to get localtime, not GMT, in this bit |
3009 | | (I think, this needs testing) */ |
3010 | 0 | t = localtime(&unixdate); |
3011 | 0 | if (!t) { |
3012 | 0 | return False; |
3013 | 0 | } |
3014 | | |
3015 | 0 | SIVAL(p,4,0); /* msecs ? */ |
3016 | 0 | SCVAL(p,8,t->tm_hour); |
3017 | 0 | SCVAL(p,9,t->tm_min); |
3018 | 0 | SCVAL(p,10,t->tm_sec); |
3019 | 0 | SCVAL(p,11,0); /* hundredths of seconds */ |
3020 | 0 | SSVALS(p,12,get_time_zone(unixdate)/60); /* timezone in minutes from GMT */ |
3021 | 0 | SSVAL(p,14,10000); /* timer interval in 0.0001 of sec */ |
3022 | 0 | SCVAL(p,16,t->tm_mday); |
3023 | 0 | SCVAL(p,17,t->tm_mon + 1); |
3024 | 0 | SSVAL(p,18,1900+t->tm_year); |
3025 | 0 | SCVAL(p,20,t->tm_wday); |
3026 | |
|
3027 | 0 | return True; |
3028 | 0 | } |
3029 | | |
3030 | | /**************************************************************************** |
3031 | | Set the user password (SamOEM version - gets plaintext). |
3032 | | ****************************************************************************/ |
3033 | | |
3034 | | static bool api_SamOEMChangePassword(struct smbd_server_connection *sconn, |
3035 | | connection_struct *conn,uint64_t vuid, |
3036 | | char *param, int tpscnt, |
3037 | | char *data, int tdscnt, |
3038 | | int mdrcnt,int mprcnt, |
3039 | | char **rdata,char **rparam, |
3040 | | int *rdata_len,int *rparam_len) |
3041 | 0 | { |
3042 | 0 | fstring user; |
3043 | 0 | char *p = get_safe_str_ptr(param,tpscnt,param,2); |
3044 | |
|
3045 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
3046 | 0 | NTSTATUS status, result; |
3047 | 0 | struct rpc_pipe_client *cli = NULL; |
3048 | 0 | struct lsa_AsciiString server, account; |
3049 | 0 | struct samr_CryptPassword password; |
3050 | 0 | struct samr_Password hash; |
3051 | 0 | int errcode = NERR_badpass; |
3052 | 0 | int bufsize; |
3053 | 0 | struct dcerpc_binding_handle *b; |
3054 | |
|
3055 | 0 | *rparam_len = 4; |
3056 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3057 | 0 | if (!*rparam) { |
3058 | 0 | return False; |
3059 | 0 | } |
3060 | | |
3061 | 0 | if (!p) { |
3062 | 0 | return False; |
3063 | 0 | } |
3064 | 0 | *rdata_len = 0; |
3065 | |
|
3066 | 0 | SSVAL(*rparam,0,NERR_badpass); |
3067 | | |
3068 | | /* |
3069 | | * Check the parameter definition is correct. |
3070 | | */ |
3071 | | |
3072 | | /* Do we have a string ? */ |
3073 | 0 | if (skip_string(param,tpscnt,p) == 0) { |
3074 | 0 | return False; |
3075 | 0 | } |
3076 | 0 | if(!strequal(p, "zsT")) { |
3077 | 0 | DEBUG(0,("api_SamOEMChangePassword: Invalid parameter string %s\n", p)); |
3078 | 0 | return False; |
3079 | 0 | } |
3080 | 0 | p = skip_string(param, tpscnt, p); |
3081 | 0 | if (!p) { |
3082 | 0 | return False; |
3083 | 0 | } |
3084 | | |
3085 | | /* Do we have a string ? */ |
3086 | 0 | if (skip_string(param,tpscnt,p) == 0) { |
3087 | 0 | return False; |
3088 | 0 | } |
3089 | 0 | if(!strequal(p, "B516B16")) { |
3090 | 0 | DEBUG(0,("api_SamOEMChangePassword: Invalid data parameter string %s\n", p)); |
3091 | 0 | return False; |
3092 | 0 | } |
3093 | 0 | p = skip_string(param,tpscnt,p); |
3094 | 0 | if (!p) { |
3095 | 0 | return False; |
3096 | 0 | } |
3097 | | /* Do we have a string ? */ |
3098 | 0 | if (skip_string(param,tpscnt,p) == 0) { |
3099 | 0 | return False; |
3100 | 0 | } |
3101 | 0 | p += pull_ascii_fstring(user,p); |
3102 | |
|
3103 | 0 | DEBUG(3,("api_SamOEMChangePassword: Change password for <%s>\n",user)); |
3104 | |
|
3105 | 0 | if (tdscnt != 532) { |
3106 | 0 | errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
3107 | 0 | goto out; |
3108 | 0 | } |
3109 | | |
3110 | 0 | bufsize = get_safe_SVAL(param,tpscnt,p,0,-1); |
3111 | 0 | if (bufsize != 532) { |
3112 | 0 | errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
3113 | 0 | goto out; |
3114 | 0 | } |
3115 | | |
3116 | 0 | memcpy(password.data, data, 516); |
3117 | 0 | memcpy(hash.hash, data+516, 16); |
3118 | |
|
3119 | 0 | status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr, |
3120 | 0 | conn->session_info, |
3121 | 0 | conn->sconn->remote_address, |
3122 | 0 | conn->sconn->local_address, |
3123 | 0 | conn->sconn->msg_ctx, |
3124 | 0 | &cli); |
3125 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3126 | 0 | DEBUG(0,("api_SamOEMChangePassword: could not connect to samr: %s\n", |
3127 | 0 | nt_errstr(status))); |
3128 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3129 | 0 | goto out; |
3130 | 0 | } |
3131 | | |
3132 | 0 | b = cli->binding_handle; |
3133 | |
|
3134 | 0 | init_lsa_AsciiString(&server, lp_netbios_name()); |
3135 | 0 | init_lsa_AsciiString(&account, user); |
3136 | |
|
3137 | 0 | status = dcerpc_samr_OemChangePasswordUser2(b, mem_ctx, |
3138 | 0 | &server, |
3139 | 0 | &account, |
3140 | 0 | &password, |
3141 | 0 | &hash, |
3142 | 0 | &result); |
3143 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3144 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3145 | 0 | goto out; |
3146 | 0 | } |
3147 | 0 | if (!NT_STATUS_IS_OK(result)) { |
3148 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
3149 | 0 | goto out; |
3150 | 0 | } |
3151 | | |
3152 | 0 | errcode = NERR_Success; |
3153 | 0 | out: |
3154 | 0 | SSVAL(*rparam,0,errcode); |
3155 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3156 | |
|
3157 | 0 | return(True); |
3158 | 0 | } |
3159 | | |
3160 | | /**************************************************************************** |
3161 | | delete a print job |
3162 | | Form: <W> <> |
3163 | | ****************************************************************************/ |
3164 | | |
3165 | | static bool api_RDosPrintJobDel(struct smbd_server_connection *sconn, |
3166 | | connection_struct *conn,uint64_t vuid, |
3167 | | char *param, int tpscnt, |
3168 | | char *data, int tdscnt, |
3169 | | int mdrcnt,int mprcnt, |
3170 | | char **rdata,char **rparam, |
3171 | | int *rdata_len,int *rparam_len) |
3172 | 0 | { |
3173 | 0 | int function = get_safe_SVAL(param,tpscnt,param,0,0); |
3174 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
3175 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
3176 | 0 | char *p = skip_string(param,tpscnt,str2); |
3177 | 0 | uint32_t jobid; |
3178 | 0 | fstring sharename; |
3179 | 0 | int errcode; |
3180 | 0 | WERROR werr = WERR_OK; |
3181 | |
|
3182 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
3183 | 0 | NTSTATUS status; |
3184 | 0 | struct rpc_pipe_client *cli = NULL; |
3185 | 0 | struct dcerpc_binding_handle *b = NULL; |
3186 | 0 | struct policy_handle handle; |
3187 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
3188 | 0 | enum spoolss_JobControl command; |
3189 | |
|
3190 | 0 | if (!str1 || !str2 || !p) { |
3191 | 0 | return False; |
3192 | 0 | } |
3193 | | /* |
3194 | | * We use 1 here not 2 as we're checking |
3195 | | * the last byte we want to access is safe. |
3196 | | */ |
3197 | 0 | if (!is_offset_safe(param,tpscnt,p,1)) { |
3198 | 0 | return False; |
3199 | 0 | } |
3200 | 0 | if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) |
3201 | 0 | return False; |
3202 | | |
3203 | | /* check it's a supported variant */ |
3204 | 0 | if (!(strcsequal(str1,"W") && strcsequal(str2,""))) |
3205 | 0 | return(False); |
3206 | | |
3207 | 0 | *rparam_len = 4; |
3208 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3209 | 0 | if (!*rparam) { |
3210 | 0 | return False; |
3211 | 0 | } |
3212 | 0 | *rdata_len = 0; |
3213 | |
|
3214 | 0 | ZERO_STRUCT(handle); |
3215 | |
|
3216 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
3217 | 0 | &ndr_table_spoolss, |
3218 | 0 | conn->session_info, |
3219 | 0 | conn->sconn->remote_address, |
3220 | 0 | conn->sconn->local_address, |
3221 | 0 | conn->sconn->msg_ctx, |
3222 | 0 | &cli); |
3223 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3224 | 0 | DEBUG(0,("api_RDosPrintJobDel: could not connect to spoolss: %s\n", |
3225 | 0 | nt_errstr(status))); |
3226 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3227 | 0 | goto out; |
3228 | 0 | } |
3229 | 0 | b = cli->binding_handle; |
3230 | |
|
3231 | 0 | ZERO_STRUCT(devmode_ctr); |
3232 | |
|
3233 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
3234 | 0 | sharename, |
3235 | 0 | "RAW", |
3236 | 0 | devmode_ctr, |
3237 | 0 | JOB_ACCESS_ADMINISTER, |
3238 | 0 | &handle, |
3239 | 0 | &werr); |
3240 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3241 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3242 | 0 | goto out; |
3243 | 0 | } |
3244 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3245 | 0 | errcode = W_ERROR_V(werr); |
3246 | 0 | goto out; |
3247 | 0 | } |
3248 | | |
3249 | | /* FIXME: formerly NERR_JobNotFound was returned if job did not exist |
3250 | | * and NERR_DestNotFound if share did not exist */ |
3251 | | |
3252 | 0 | errcode = NERR_Success; |
3253 | |
|
3254 | 0 | switch (function) { |
3255 | 0 | case 81: /* delete */ |
3256 | 0 | command = SPOOLSS_JOB_CONTROL_DELETE; |
3257 | 0 | break; |
3258 | 0 | case 82: /* pause */ |
3259 | 0 | command = SPOOLSS_JOB_CONTROL_PAUSE; |
3260 | 0 | break; |
3261 | 0 | case 83: /* resume */ |
3262 | 0 | command = SPOOLSS_JOB_CONTROL_RESUME; |
3263 | 0 | break; |
3264 | 0 | default: |
3265 | 0 | errcode = NERR_notsupported; |
3266 | 0 | goto out; |
3267 | 0 | } |
3268 | | |
3269 | 0 | status = dcerpc_spoolss_SetJob(b, mem_ctx, |
3270 | 0 | &handle, |
3271 | 0 | jobid, |
3272 | 0 | NULL, /* unique ptr ctr */ |
3273 | 0 | command, |
3274 | 0 | &werr); |
3275 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3276 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3277 | 0 | goto out; |
3278 | 0 | } |
3279 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3280 | 0 | errcode = W_ERROR_V(werr); |
3281 | 0 | goto out; |
3282 | 0 | } |
3283 | | |
3284 | 0 | out: |
3285 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
3286 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
3287 | 0 | } |
3288 | |
|
3289 | 0 | SSVAL(*rparam,0,errcode); |
3290 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3291 | |
|
3292 | 0 | return(True); |
3293 | 0 | } |
3294 | | |
3295 | | /**************************************************************************** |
3296 | | Purge a print queue - or pause or resume it. |
3297 | | ****************************************************************************/ |
3298 | | |
3299 | | static bool api_WPrintQueueCtrl(struct smbd_server_connection *sconn, |
3300 | | connection_struct *conn,uint64_t vuid, |
3301 | | char *param, int tpscnt, |
3302 | | char *data, int tdscnt, |
3303 | | int mdrcnt,int mprcnt, |
3304 | | char **rdata,char **rparam, |
3305 | | int *rdata_len,int *rparam_len) |
3306 | 0 | { |
3307 | 0 | int function = get_safe_SVAL(param,tpscnt,param,0,0); |
3308 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
3309 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
3310 | 0 | char *QueueName = skip_string(param,tpscnt,str2); |
3311 | 0 | int errcode = NERR_notsupported; |
3312 | 0 | WERROR werr = WERR_OK; |
3313 | 0 | NTSTATUS status; |
3314 | |
|
3315 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
3316 | 0 | struct rpc_pipe_client *cli = NULL; |
3317 | 0 | struct dcerpc_binding_handle *b = NULL; |
3318 | 0 | struct policy_handle handle; |
3319 | 0 | struct spoolss_SetPrinterInfoCtr info_ctr; |
3320 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
3321 | 0 | struct sec_desc_buf secdesc_ctr; |
3322 | 0 | enum spoolss_PrinterControl command = SPOOLSS_PRINTER_CONTROL_UNPAUSE; |
3323 | |
|
3324 | 0 | if (!str1 || !str2 || !QueueName) { |
3325 | 0 | return False; |
3326 | 0 | } |
3327 | | |
3328 | | /* check it's a supported variant */ |
3329 | 0 | if (!(strcsequal(str1,"z") && strcsequal(str2,""))) |
3330 | 0 | return(False); |
3331 | | |
3332 | 0 | *rparam_len = 4; |
3333 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3334 | 0 | if (!*rparam) { |
3335 | 0 | return False; |
3336 | 0 | } |
3337 | 0 | *rdata_len = 0; |
3338 | |
|
3339 | 0 | if (skip_string(param,tpscnt,QueueName) == NULL) { |
3340 | 0 | return False; |
3341 | 0 | } |
3342 | | |
3343 | 0 | ZERO_STRUCT(handle); |
3344 | |
|
3345 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
3346 | 0 | &ndr_table_spoolss, |
3347 | 0 | conn->session_info, |
3348 | 0 | conn->sconn->remote_address, |
3349 | 0 | conn->sconn->local_address, |
3350 | 0 | conn->sconn->msg_ctx, |
3351 | 0 | &cli); |
3352 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3353 | 0 | DEBUG(0,("api_WPrintQueueCtrl: could not connect to spoolss: %s\n", |
3354 | 0 | nt_errstr(status))); |
3355 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3356 | 0 | goto out; |
3357 | 0 | } |
3358 | 0 | b = cli->binding_handle; |
3359 | |
|
3360 | 0 | ZERO_STRUCT(devmode_ctr); |
3361 | |
|
3362 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
3363 | 0 | QueueName, |
3364 | 0 | NULL, |
3365 | 0 | devmode_ctr, |
3366 | 0 | PRINTER_ACCESS_ADMINISTER, |
3367 | 0 | &handle, |
3368 | 0 | &werr); |
3369 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3370 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3371 | 0 | goto out; |
3372 | 0 | } |
3373 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3374 | 0 | errcode = W_ERROR_V(werr); |
3375 | 0 | goto out; |
3376 | 0 | } |
3377 | | |
3378 | 0 | switch (function) { |
3379 | 0 | case 74: /* Pause queue */ |
3380 | 0 | command = SPOOLSS_PRINTER_CONTROL_PAUSE; |
3381 | 0 | break; |
3382 | 0 | case 75: /* Resume queue */ |
3383 | 0 | command = SPOOLSS_PRINTER_CONTROL_RESUME; |
3384 | 0 | break; |
3385 | 0 | case 103: /* Purge */ |
3386 | 0 | command = SPOOLSS_PRINTER_CONTROL_PURGE; |
3387 | 0 | break; |
3388 | 0 | default: |
3389 | 0 | werr = WERR_NOT_SUPPORTED; |
3390 | 0 | break; |
3391 | 0 | } |
3392 | | |
3393 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3394 | 0 | errcode = W_ERROR_V(werr); |
3395 | 0 | goto out; |
3396 | 0 | } |
3397 | | |
3398 | 0 | ZERO_STRUCT(info_ctr); |
3399 | 0 | ZERO_STRUCT(secdesc_ctr); |
3400 | |
|
3401 | 0 | status = dcerpc_spoolss_SetPrinter(b, mem_ctx, |
3402 | 0 | &handle, |
3403 | 0 | &info_ctr, |
3404 | 0 | &devmode_ctr, |
3405 | 0 | &secdesc_ctr, |
3406 | 0 | command, |
3407 | 0 | &werr); |
3408 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3409 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3410 | 0 | goto out; |
3411 | 0 | } |
3412 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3413 | 0 | errcode = W_ERROR_V(werr); |
3414 | 0 | goto out; |
3415 | 0 | } |
3416 | | |
3417 | 0 | errcode = W_ERROR_V(werr); |
3418 | |
|
3419 | 0 | out: |
3420 | |
|
3421 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
3422 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
3423 | 0 | } |
3424 | |
|
3425 | 0 | SSVAL(*rparam,0,errcode); |
3426 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3427 | |
|
3428 | 0 | return(True); |
3429 | 0 | } |
3430 | | |
3431 | | /**************************************************************************** |
3432 | | set the property of a print job (undocumented?) |
3433 | | ? function = 0xb -> set name of print job |
3434 | | ? function = 0x6 -> move print job up/down |
3435 | | Form: <WWsTP> <WWzWWDDzzzzzzzzzzlz> |
3436 | | or <WWsTP> <WB21BB16B10zWWzDDz> |
3437 | | ****************************************************************************/ |
3438 | | |
3439 | | static int check_printjob_info(struct pack_desc* desc, |
3440 | | int uLevel, char* id) |
3441 | 0 | { |
3442 | 0 | desc->subformat = NULL; |
3443 | 0 | switch( uLevel ) { |
3444 | 0 | case 0: desc->format = "W"; break; |
3445 | 0 | case 1: desc->format = "WB21BB16B10zWWzDDz"; break; |
3446 | 0 | case 2: desc->format = "WWzWWDDzz"; break; |
3447 | 0 | case 3: desc->format = "WWzWWDDzzzzzzzzzzlz"; break; |
3448 | 0 | case 4: desc->format = "WWzWWDDzzzzzDDDDDDD"; break; |
3449 | 0 | default: |
3450 | 0 | DEBUG(0,("check_printjob_info: invalid level %d\n", |
3451 | 0 | uLevel )); |
3452 | 0 | return False; |
3453 | 0 | } |
3454 | 0 | if (id == NULL || strcmp(desc->format,id) != 0) { |
3455 | 0 | DEBUG(0,("check_printjob_info: invalid format %s\n", |
3456 | 0 | id ? id : "<NULL>" )); |
3457 | 0 | return False; |
3458 | 0 | } |
3459 | 0 | return True; |
3460 | 0 | } |
3461 | | |
3462 | | static bool api_PrintJobInfo(struct smbd_server_connection *sconn, |
3463 | | connection_struct *conn, uint64_t vuid, |
3464 | | char *param, int tpscnt, |
3465 | | char *data, int tdscnt, |
3466 | | int mdrcnt,int mprcnt, |
3467 | | char **rdata,char **rparam, |
3468 | | int *rdata_len,int *rparam_len) |
3469 | 0 | { |
3470 | 0 | struct pack_desc desc; |
3471 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
3472 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
3473 | 0 | char *p = skip_string(param,tpscnt,str2); |
3474 | 0 | uint32_t jobid; |
3475 | 0 | fstring sharename; |
3476 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,2,-1); |
3477 | 0 | int function = get_safe_SVAL(param,tpscnt,p,4,-1); |
3478 | 0 | int errcode; |
3479 | |
|
3480 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
3481 | 0 | WERROR werr; |
3482 | 0 | NTSTATUS status; |
3483 | 0 | struct rpc_pipe_client *cli = NULL; |
3484 | 0 | struct dcerpc_binding_handle *b = NULL; |
3485 | 0 | struct policy_handle handle; |
3486 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
3487 | 0 | struct spoolss_JobInfoContainer ctr; |
3488 | 0 | union spoolss_JobInfo info; |
3489 | 0 | struct spoolss_SetJobInfo1 info1; |
3490 | |
|
3491 | 0 | if (!str1 || !str2 || !p) { |
3492 | 0 | return False; |
3493 | 0 | } |
3494 | | /* |
3495 | | * We use 1 here not 2 as we're checking |
3496 | | * the last byte we want to access is safe. |
3497 | | */ |
3498 | 0 | if (!is_offset_safe(param,tpscnt,p,1)) { |
3499 | 0 | return False; |
3500 | 0 | } |
3501 | 0 | if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) |
3502 | 0 | return False; |
3503 | 0 | *rparam_len = 4; |
3504 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3505 | 0 | if (!*rparam) { |
3506 | 0 | return False; |
3507 | 0 | } |
3508 | | |
3509 | 0 | *rdata_len = 0; |
3510 | | |
3511 | | /* check it's a supported variant */ |
3512 | 0 | if ((strcmp(str1,"WWsTP")) || |
3513 | 0 | (!check_printjob_info(&desc,uLevel,str2))) |
3514 | 0 | return(False); |
3515 | | |
3516 | 0 | errcode = NERR_notsupported; |
3517 | |
|
3518 | 0 | switch (function) { |
3519 | 0 | case 0xb: |
3520 | | /* change print job name, data gives the name */ |
3521 | 0 | break; |
3522 | 0 | default: |
3523 | 0 | goto out; |
3524 | 0 | } |
3525 | | |
3526 | 0 | ZERO_STRUCT(handle); |
3527 | |
|
3528 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
3529 | 0 | &ndr_table_spoolss, |
3530 | 0 | conn->session_info, |
3531 | 0 | conn->sconn->remote_address, |
3532 | 0 | conn->sconn->local_address, |
3533 | 0 | conn->sconn->msg_ctx, |
3534 | 0 | &cli); |
3535 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3536 | 0 | DEBUG(0,("api_PrintJobInfo: could not connect to spoolss: %s\n", |
3537 | 0 | nt_errstr(status))); |
3538 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3539 | 0 | goto out; |
3540 | 0 | } |
3541 | 0 | b = cli->binding_handle; |
3542 | |
|
3543 | 0 | ZERO_STRUCT(devmode_ctr); |
3544 | |
|
3545 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
3546 | 0 | sharename, |
3547 | 0 | "RAW", |
3548 | 0 | devmode_ctr, |
3549 | 0 | PRINTER_ACCESS_USE, |
3550 | 0 | &handle, |
3551 | 0 | &werr); |
3552 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3553 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3554 | 0 | goto out; |
3555 | 0 | } |
3556 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3557 | 0 | errcode = W_ERROR_V(werr); |
3558 | 0 | goto out; |
3559 | 0 | } |
3560 | | |
3561 | 0 | werr = rpccli_spoolss_getjob(cli, mem_ctx, |
3562 | 0 | &handle, |
3563 | 0 | jobid, |
3564 | 0 | 1, /* level */ |
3565 | 0 | 0, /* offered */ |
3566 | 0 | &info); |
3567 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3568 | 0 | errcode = W_ERROR_V(werr); |
3569 | 0 | goto out; |
3570 | 0 | } |
3571 | | |
3572 | 0 | ZERO_STRUCT(ctr); |
3573 | |
|
3574 | 0 | info1.job_id = info.info1.job_id; |
3575 | 0 | info1.printer_name = info.info1.printer_name; |
3576 | 0 | info1.user_name = info.info1.user_name; |
3577 | 0 | info1.document_name = data; |
3578 | 0 | info1.data_type = info.info1.data_type; |
3579 | 0 | info1.text_status = info.info1.text_status; |
3580 | 0 | info1.status = info.info1.status; |
3581 | 0 | info1.priority = info.info1.priority; |
3582 | 0 | info1.position = info.info1.position; |
3583 | 0 | info1.total_pages = info.info1.total_pages; |
3584 | 0 | info1.pages_printed = info.info1.pages_printed; |
3585 | 0 | info1.submitted = info.info1.submitted; |
3586 | |
|
3587 | 0 | ctr.level = 1; |
3588 | 0 | ctr.info.info1 = &info1; |
3589 | |
|
3590 | 0 | status = dcerpc_spoolss_SetJob(b, mem_ctx, |
3591 | 0 | &handle, |
3592 | 0 | jobid, |
3593 | 0 | &ctr, |
3594 | 0 | 0, |
3595 | 0 | &werr); |
3596 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3597 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3598 | 0 | goto out; |
3599 | 0 | } |
3600 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3601 | 0 | errcode = W_ERROR_V(werr); |
3602 | 0 | goto out; |
3603 | 0 | } |
3604 | | |
3605 | 0 | errcode = NERR_Success; |
3606 | 0 | out: |
3607 | |
|
3608 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
3609 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
3610 | 0 | } |
3611 | |
|
3612 | 0 | SSVALS(*rparam,0,errcode); |
3613 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3614 | |
|
3615 | 0 | return(True); |
3616 | 0 | } |
3617 | | |
3618 | | |
3619 | | /**************************************************************************** |
3620 | | Get info about the server. |
3621 | | ****************************************************************************/ |
3622 | | |
3623 | | static bool api_RNetServerGetInfo(struct smbd_server_connection *sconn, |
3624 | | connection_struct *conn,uint64_t vuid, |
3625 | | char *param, int tpscnt, |
3626 | | char *data, int tdscnt, |
3627 | | int mdrcnt,int mprcnt, |
3628 | | char **rdata,char **rparam, |
3629 | | int *rdata_len,int *rparam_len) |
3630 | 0 | { |
3631 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
3632 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
3633 | 0 | char *p = skip_string(param,tpscnt,str2); |
3634 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
3635 | 0 | char *p2; |
3636 | 0 | int struct_len; |
3637 | |
|
3638 | 0 | NTSTATUS status; |
3639 | 0 | WERROR werr; |
3640 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
3641 | 0 | struct rpc_pipe_client *cli = NULL; |
3642 | 0 | union srvsvc_NetSrvInfo info; |
3643 | 0 | int errcode; |
3644 | 0 | struct dcerpc_binding_handle *b; |
3645 | |
|
3646 | 0 | if (!str1 || !str2 || !p) { |
3647 | 0 | return False; |
3648 | 0 | } |
3649 | | |
3650 | 0 | DEBUG(4,("NetServerGetInfo level %d\n",uLevel)); |
3651 | | |
3652 | | /* check it's a supported variant */ |
3653 | 0 | if (!prefix_ok(str1,"WrLh")) { |
3654 | 0 | return False; |
3655 | 0 | } |
3656 | | |
3657 | 0 | switch( uLevel ) { |
3658 | 0 | case 0: |
3659 | 0 | if (strcmp(str2,"B16") != 0) { |
3660 | 0 | return False; |
3661 | 0 | } |
3662 | 0 | struct_len = 16; |
3663 | 0 | break; |
3664 | 0 | case 1: |
3665 | 0 | if (strcmp(str2,"B16BBDz") != 0) { |
3666 | 0 | return False; |
3667 | 0 | } |
3668 | 0 | struct_len = 26; |
3669 | 0 | break; |
3670 | 0 | case 2: |
3671 | 0 | if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWz")!= 0) { |
3672 | 0 | return False; |
3673 | 0 | } |
3674 | 0 | struct_len = 134; |
3675 | 0 | break; |
3676 | 0 | case 3: |
3677 | 0 | if (strcmp(str2,"B16BBDzDDDWWzWWWWWWWBB21zWWWWWWWWWWWWWWWWWWWWWWzDWz") != 0) { |
3678 | 0 | return False; |
3679 | 0 | } |
3680 | 0 | struct_len = 144; |
3681 | 0 | break; |
3682 | 0 | case 20: |
3683 | 0 | if (strcmp(str2,"DN") != 0) { |
3684 | 0 | return False; |
3685 | 0 | } |
3686 | 0 | struct_len = 6; |
3687 | 0 | break; |
3688 | 0 | case 50: |
3689 | 0 | if (strcmp(str2,"B16BBDzWWzzz") != 0) { |
3690 | 0 | return False; |
3691 | 0 | } |
3692 | 0 | struct_len = 42; |
3693 | 0 | break; |
3694 | 0 | default: |
3695 | 0 | return False; |
3696 | 0 | } |
3697 | | |
3698 | 0 | *rdata_len = mdrcnt; |
3699 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
3700 | 0 | if (!*rdata) { |
3701 | 0 | return False; |
3702 | 0 | } |
3703 | | |
3704 | 0 | p = *rdata; |
3705 | 0 | p2 = p + struct_len; |
3706 | |
|
3707 | 0 | status = rpc_pipe_open_interface(mem_ctx, &ndr_table_srvsvc, |
3708 | 0 | conn->session_info, |
3709 | 0 | conn->sconn->remote_address, |
3710 | 0 | conn->sconn->local_address, |
3711 | 0 | conn->sconn->msg_ctx, |
3712 | 0 | &cli); |
3713 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3714 | 0 | DEBUG(0,("api_RNetServerGetInfo: could not connect to srvsvc: %s\n", |
3715 | 0 | nt_errstr(status))); |
3716 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3717 | 0 | goto out; |
3718 | 0 | } |
3719 | | |
3720 | 0 | b = cli->binding_handle; |
3721 | |
|
3722 | 0 | status = dcerpc_srvsvc_NetSrvGetInfo(b, mem_ctx, |
3723 | 0 | NULL, |
3724 | 0 | 101, |
3725 | 0 | &info, |
3726 | 0 | &werr); |
3727 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3728 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3729 | 0 | goto out; |
3730 | 0 | } |
3731 | 0 | if (!W_ERROR_IS_OK(werr)) { |
3732 | 0 | errcode = W_ERROR_V(werr); |
3733 | 0 | goto out; |
3734 | 0 | } |
3735 | | |
3736 | 0 | if (info.info101 == NULL) { |
3737 | 0 | errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
3738 | 0 | goto out; |
3739 | 0 | } |
3740 | | |
3741 | 0 | if (uLevel != 20) { |
3742 | 0 | size_t len = 0; |
3743 | 0 | status = srvstr_push(NULL, 0, p, info.info101->server_name, 16, |
3744 | 0 | STR_ASCII|STR_UPPER|STR_TERMINATE, &len); |
3745 | 0 | if (!NT_STATUS_IS_OK(status)) { |
3746 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
3747 | 0 | goto out; |
3748 | 0 | } |
3749 | 0 | } |
3750 | 0 | p += 16; |
3751 | 0 | if (uLevel > 0) { |
3752 | 0 | SCVAL(p,0,info.info101->version_major); |
3753 | 0 | SCVAL(p,1,info.info101->version_minor); |
3754 | 0 | SIVAL(p,2,info.info101->server_type); |
3755 | |
|
3756 | 0 | if (mdrcnt == struct_len) { |
3757 | 0 | SIVAL(p,6,0); |
3758 | 0 | } else { |
3759 | 0 | SIVAL(p,6,PTR_DIFF(p2,*rdata)); |
3760 | 0 | if (mdrcnt - struct_len <= 0) { |
3761 | 0 | return false; |
3762 | 0 | } |
3763 | 0 | push_ascii(p2, |
3764 | 0 | info.info101->comment, |
3765 | 0 | MIN(mdrcnt - struct_len, |
3766 | 0 | MAX_SERVER_STRING_LENGTH), |
3767 | 0 | STR_TERMINATE); |
3768 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3769 | 0 | if (!p2) { |
3770 | 0 | return False; |
3771 | 0 | } |
3772 | 0 | } |
3773 | 0 | } |
3774 | | |
3775 | 0 | if (uLevel > 1) { |
3776 | 0 | return False; /* not yet implemented */ |
3777 | 0 | } |
3778 | | |
3779 | 0 | errcode = NERR_Success; |
3780 | |
|
3781 | 0 | out: |
3782 | |
|
3783 | 0 | *rdata_len = PTR_DIFF(p2,*rdata); |
3784 | |
|
3785 | 0 | *rparam_len = 6; |
3786 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3787 | 0 | if (!*rparam) { |
3788 | 0 | return False; |
3789 | 0 | } |
3790 | 0 | SSVAL(*rparam,0,errcode); |
3791 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3792 | 0 | SSVAL(*rparam,4,*rdata_len); |
3793 | |
|
3794 | 0 | return True; |
3795 | 0 | } |
3796 | | |
3797 | | /**************************************************************************** |
3798 | | Get info about the server. |
3799 | | ****************************************************************************/ |
3800 | | |
3801 | | static bool api_NetWkstaGetInfo(struct smbd_server_connection *sconn, |
3802 | | connection_struct *conn,uint64_t vuid, |
3803 | | char *param, int tpscnt, |
3804 | | char *data, int tdscnt, |
3805 | | int mdrcnt,int mprcnt, |
3806 | | char **rdata,char **rparam, |
3807 | | int *rdata_len,int *rparam_len) |
3808 | 0 | { |
3809 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
3810 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
3811 | 0 | char *p = skip_string(param,tpscnt,str2); |
3812 | 0 | char *p2; |
3813 | 0 | char *endp; |
3814 | 0 | int level = get_safe_SVAL(param,tpscnt,p,0,-1); |
3815 | |
|
3816 | 0 | if (!str1 || !str2 || !p) { |
3817 | 0 | return False; |
3818 | 0 | } |
3819 | | |
3820 | 0 | DEBUG(4,("NetWkstaGetInfo level %d\n",level)); |
3821 | |
|
3822 | 0 | *rparam_len = 6; |
3823 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
3824 | 0 | if (!*rparam) { |
3825 | 0 | return False; |
3826 | 0 | } |
3827 | | |
3828 | | /* check it's a supported variant */ |
3829 | 0 | if (!(level==10 && strcsequal(str1,"WrLh") && strcsequal(str2,"zzzBBzz"))) { |
3830 | 0 | return False; |
3831 | 0 | } |
3832 | | |
3833 | 0 | *rdata_len = mdrcnt + 1024; |
3834 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
3835 | 0 | if (!*rdata) { |
3836 | 0 | return False; |
3837 | 0 | } |
3838 | | |
3839 | 0 | SSVAL(*rparam,0,NERR_Success); |
3840 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
3841 | |
|
3842 | 0 | p = *rdata; |
3843 | 0 | endp = *rdata + *rdata_len; |
3844 | |
|
3845 | 0 | p2 = get_safe_ptr(*rdata,*rdata_len,p,22); |
3846 | 0 | if (!p2) { |
3847 | 0 | return False; |
3848 | 0 | } |
3849 | | |
3850 | 0 | SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* host name */ |
3851 | 0 | strlcpy(p2,get_local_machine_name(),PTR_DIFF(endp,p2)); |
3852 | 0 | if (!strupper_m(p2)) { |
3853 | 0 | return false; |
3854 | 0 | } |
3855 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3856 | 0 | if (!p2) { |
3857 | 0 | return False; |
3858 | 0 | } |
3859 | 0 | p += 4; |
3860 | |
|
3861 | 0 | SIVAL(p,0,PTR_DIFF(p2,*rdata)); |
3862 | 0 | strlcpy(p2,conn->session_info->unix_info->sanitized_username,PTR_DIFF(endp,p2)); |
3863 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3864 | 0 | if (!p2) { |
3865 | 0 | return False; |
3866 | 0 | } |
3867 | 0 | p += 4; |
3868 | |
|
3869 | 0 | SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* login domain */ |
3870 | 0 | strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); |
3871 | 0 | if (!strupper_m(p2)) { |
3872 | 0 | return false; |
3873 | 0 | } |
3874 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3875 | 0 | if (!p2) { |
3876 | 0 | return False; |
3877 | 0 | } |
3878 | 0 | p += 4; |
3879 | |
|
3880 | 0 | SCVAL(p,0,SAMBA_MAJOR_NBT_ANNOUNCE_VERSION); /* system version - e.g 4 in 4.1 */ |
3881 | 0 | SCVAL(p,1,SAMBA_MINOR_NBT_ANNOUNCE_VERSION); /* system version - e.g .1 in 4.1 */ |
3882 | 0 | p += 2; |
3883 | |
|
3884 | 0 | SIVAL(p,0,PTR_DIFF(p2,*rdata)); |
3885 | 0 | strlcpy(p2,lp_workgroup(),PTR_DIFF(endp,p2)); /* don't know. login domain?? */ |
3886 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3887 | 0 | if (!p2) { |
3888 | 0 | return False; |
3889 | 0 | } |
3890 | 0 | p += 4; |
3891 | |
|
3892 | 0 | SIVAL(p,0,PTR_DIFF(p2,*rdata)); /* don't know */ |
3893 | 0 | strlcpy(p2,"",PTR_DIFF(endp,p2)); |
3894 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
3895 | 0 | if (!p2) { |
3896 | 0 | return False; |
3897 | 0 | } |
3898 | 0 | p += 4; |
3899 | |
|
3900 | 0 | *rdata_len = PTR_DIFF(p2,*rdata); |
3901 | |
|
3902 | 0 | SSVAL(*rparam,4,*rdata_len); |
3903 | |
|
3904 | 0 | return True; |
3905 | 0 | } |
3906 | | |
3907 | | /**************************************************************************** |
3908 | | get info about a user |
3909 | | |
3910 | | struct user_info_11 { |
3911 | | char usri11_name[21]; 0-20 |
3912 | | char usri11_pad; 21 |
3913 | | char *usri11_comment; 22-25 |
3914 | | char *usri11_usr_comment; 26-29 |
3915 | | unsigned short usri11_priv; 30-31 |
3916 | | unsigned long usri11_auth_flags; 32-35 |
3917 | | long usri11_password_age; 36-39 |
3918 | | char *usri11_homedir; 40-43 |
3919 | | char *usri11_parms; 44-47 |
3920 | | long usri11_last_logon; 48-51 |
3921 | | long usri11_last_logoff; 52-55 |
3922 | | unsigned short usri11_bad_pw_count; 56-57 |
3923 | | unsigned short usri11_num_logons; 58-59 |
3924 | | char *usri11_logon_server; 60-63 |
3925 | | unsigned short usri11_country_code; 64-65 |
3926 | | char *usri11_workstations; 66-69 |
3927 | | unsigned long usri11_max_storage; 70-73 |
3928 | | unsigned short usri11_units_per_week; 74-75 |
3929 | | unsigned char *usri11_logon_hours; 76-79 |
3930 | | unsigned short usri11_code_page; 80-81 |
3931 | | }; |
3932 | | |
3933 | | where: |
3934 | | |
3935 | | usri11_name specifies the user name for which information is retrieved |
3936 | | |
3937 | | usri11_pad aligns the next data structure element to a word boundary |
3938 | | |
3939 | | usri11_comment is a null terminated ASCII comment |
3940 | | |
3941 | | usri11_user_comment is a null terminated ASCII comment about the user |
3942 | | |
3943 | | usri11_priv specifies the level of the privilege assigned to the user. |
3944 | | The possible values are: |
3945 | | |
3946 | | Name Value Description |
3947 | | USER_PRIV_GUEST 0 Guest privilege |
3948 | | USER_PRIV_USER 1 User privilege |
3949 | | USER_PRV_ADMIN 2 Administrator privilege |
3950 | | |
3951 | | usri11_auth_flags specifies the account operator privileges. The |
3952 | | possible values are: |
3953 | | |
3954 | | Name Value Description |
3955 | | AF_OP_PRINT 0 Print operator |
3956 | | |
3957 | | |
3958 | | Leach, Naik [Page 28] |
3959 | | |
3960 | | |
3961 | | |
3962 | | INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 |
3963 | | |
3964 | | |
3965 | | AF_OP_COMM 1 Communications operator |
3966 | | AF_OP_SERVER 2 Server operator |
3967 | | AF_OP_ACCOUNTS 3 Accounts operator |
3968 | | |
3969 | | |
3970 | | usri11_password_age specifies how many seconds have elapsed since the |
3971 | | password was last changed. |
3972 | | |
3973 | | usri11_home_dir points to a null terminated ASCII string that contains |
3974 | | the path name of the user's home directory. |
3975 | | |
3976 | | usri11_parms points to a null terminated ASCII string that is set |
3977 | | aside for use by applications. |
3978 | | |
3979 | | usri11_last_logon specifies the time when the user last logged on. |
3980 | | This value is stored as the number of seconds elapsed since |
3981 | | 00:00:00, January 1, 1970. |
3982 | | |
3983 | | usri11_last_logoff specifies the time when the user last logged off. |
3984 | | This value is stored as the number of seconds elapsed since |
3985 | | 00:00:00, January 1, 1970. A value of 0 means the last logoff |
3986 | | time is unknown. |
3987 | | |
3988 | | usri11_bad_pw_count specifies the number of incorrect passwords |
3989 | | entered since the last successful logon. |
3990 | | |
3991 | | usri11_log1_num_logons specifies the number of times this user has |
3992 | | logged on. A value of -1 means the number of logons is unknown. |
3993 | | |
3994 | | usri11_logon_server points to a null terminated ASCII string that |
3995 | | contains the name of the server to which logon requests are sent. |
3996 | | A null string indicates logon requests should be sent to the |
3997 | | domain controller. |
3998 | | |
3999 | | usri11_country_code specifies the country code for the user's language |
4000 | | of choice. |
4001 | | |
4002 | | usri11_workstations points to a null terminated ASCII string that |
4003 | | contains the names of workstations the user may log on from. |
4004 | | There may be up to 8 workstations, with the names separated by |
4005 | | commas. A null strings indicates there are no restrictions. |
4006 | | |
4007 | | usri11_max_storage specifies the maximum amount of disk space the user |
4008 | | can occupy. A value of 0xffffffff indicates there are no |
4009 | | restrictions. |
4010 | | |
4011 | | usri11_units_per_week specifies the equal number of time units into |
4012 | | which a week is divided. This value must be equal to 168. |
4013 | | |
4014 | | usri11_logon_hours points to a 21 byte (168 bits) string that |
4015 | | specifies the time during which the user can log on. Each bit |
4016 | | represents one unique hour in a week. The first bit (bit 0, word |
4017 | | 0) is Sunday, 0:00 to 0:59, the second bit (bit 1, word 0) is |
4018 | | |
4019 | | |
4020 | | |
4021 | | Leach, Naik [Page 29] |
4022 | | |
4023 | | |
4024 | | |
4025 | | INTERNET-DRAFT CIFS Remote Admin Protocol January 10, 1997 |
4026 | | |
4027 | | |
4028 | | Sunday, 1:00 to 1:59 and so on. A null pointer indicates there |
4029 | | are no restrictions. |
4030 | | |
4031 | | usri11_code_page specifies the code page for the user's language of |
4032 | | choice |
4033 | | |
4034 | | All of the pointers in this data structure need to be treated |
4035 | | specially. The pointer is a 32 bit pointer. The higher 16 bits need |
4036 | | to be ignored. The converter word returned in the parameters section |
4037 | | needs to be subtracted from the lower 16 bits to calculate an offset |
4038 | | into the return buffer where this ASCII string resides. |
4039 | | |
4040 | | There is no auxiliary data in the response. |
4041 | | |
4042 | | ****************************************************************************/ |
4043 | | |
4044 | | #define usri11_name 0 |
4045 | | #define usri11_pad 21 |
4046 | | #define usri11_comment 22 |
4047 | | #define usri11_usr_comment 26 |
4048 | | #define usri11_full_name 30 |
4049 | | #define usri11_priv 34 |
4050 | | #define usri11_auth_flags 36 |
4051 | | #define usri11_password_age 40 |
4052 | | #define usri11_homedir 44 |
4053 | | #define usri11_parms 48 |
4054 | | #define usri11_last_logon 52 |
4055 | | #define usri11_last_logoff 56 |
4056 | | #define usri11_bad_pw_count 60 |
4057 | | #define usri11_num_logons 62 |
4058 | | #define usri11_logon_server 64 |
4059 | | #define usri11_country_code 68 |
4060 | | #define usri11_workstations 70 |
4061 | | #define usri11_max_storage 74 |
4062 | | #define usri11_units_per_week 78 |
4063 | | #define usri11_logon_hours 80 |
4064 | | #define usri11_code_page 84 |
4065 | 0 | #define usri11_end 86 |
4066 | | |
4067 | | static bool api_RNetUserGetInfo(struct smbd_server_connection *sconn, |
4068 | | connection_struct *conn, uint64_t vuid, |
4069 | | char *param, int tpscnt, |
4070 | | char *data, int tdscnt, |
4071 | | int mdrcnt,int mprcnt, |
4072 | | char **rdata,char **rparam, |
4073 | | int *rdata_len,int *rparam_len) |
4074 | 0 | { |
4075 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4076 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4077 | 0 | char *UserName = skip_string(param,tpscnt,str2); |
4078 | 0 | char *p = skip_string(param,tpscnt,UserName); |
4079 | 0 | int uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
4080 | 0 | char *p2; |
4081 | 0 | char *endp; |
4082 | 0 | const char *level_string; |
4083 | |
|
4084 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
4085 | 0 | NTSTATUS status, result; |
4086 | 0 | struct rpc_pipe_client *cli = NULL; |
4087 | 0 | struct policy_handle connect_handle, domain_handle, user_handle; |
4088 | 0 | struct lsa_String domain_name; |
4089 | 0 | struct dom_sid2 *domain_sid; |
4090 | 0 | struct lsa_String names; |
4091 | 0 | struct samr_Ids rids; |
4092 | 0 | struct samr_Ids types; |
4093 | 0 | int errcode = W_ERROR_V(WERR_NERR_USERNOTFOUND); |
4094 | 0 | uint32_t rid; |
4095 | 0 | union samr_UserInfo *info; |
4096 | 0 | struct dcerpc_binding_handle *b = NULL; |
4097 | |
|
4098 | 0 | if (!str1 || !str2 || !UserName || !p) { |
4099 | 0 | return False; |
4100 | 0 | } |
4101 | | |
4102 | 0 | *rparam_len = 6; |
4103 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
4104 | 0 | if (!*rparam) { |
4105 | 0 | return False; |
4106 | 0 | } |
4107 | | |
4108 | 0 | DEBUG(4,("RNetUserGetInfo level=%d\n", uLevel)); |
4109 | | |
4110 | | /* check it's a supported variant */ |
4111 | 0 | if (strcmp(str1,"zWrLh") != 0) { |
4112 | 0 | return False; |
4113 | 0 | } |
4114 | 0 | switch( uLevel ) { |
4115 | 0 | case 0: level_string = "B21"; break; |
4116 | 0 | case 1: level_string = "B21BB16DWzzWz"; break; |
4117 | 0 | case 2: level_string = "B21BB16DWzzWzDzzzzDDDDWb21WWzWW"; break; |
4118 | 0 | case 10: level_string = "B21Bzzz"; break; |
4119 | 0 | case 11: level_string = "B21BzzzWDDzzDDWWzWzDWb21W"; break; |
4120 | 0 | default: return False; |
4121 | 0 | } |
4122 | | |
4123 | 0 | if (strcmp(level_string,str2) != 0) { |
4124 | 0 | return False; |
4125 | 0 | } |
4126 | | |
4127 | 0 | *rdata_len = mdrcnt + 1024; |
4128 | 0 | *rdata = smb_realloc_limit(*rdata,*rdata_len); |
4129 | 0 | if (!*rdata) { |
4130 | 0 | return False; |
4131 | 0 | } |
4132 | | |
4133 | 0 | p = *rdata; |
4134 | 0 | endp = *rdata + *rdata_len; |
4135 | 0 | p2 = get_safe_ptr(*rdata,*rdata_len,p,usri11_end); |
4136 | 0 | if (!p2) { |
4137 | 0 | return False; |
4138 | 0 | } |
4139 | | |
4140 | 0 | ZERO_STRUCT(connect_handle); |
4141 | 0 | ZERO_STRUCT(domain_handle); |
4142 | 0 | ZERO_STRUCT(user_handle); |
4143 | |
|
4144 | 0 | status = rpc_pipe_open_interface(mem_ctx, &ndr_table_samr, |
4145 | 0 | conn->session_info, |
4146 | 0 | conn->sconn->remote_address, |
4147 | 0 | conn->sconn->local_address, |
4148 | 0 | conn->sconn->msg_ctx, |
4149 | 0 | &cli); |
4150 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4151 | 0 | DEBUG(0,("api_RNetUserGetInfo: could not connect to samr: %s\n", |
4152 | 0 | nt_errstr(status))); |
4153 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4154 | 0 | goto out; |
4155 | 0 | } |
4156 | | |
4157 | 0 | b = cli->binding_handle; |
4158 | |
|
4159 | 0 | status = dcerpc_samr_Connect2(b, mem_ctx, |
4160 | 0 | lp_netbios_name(), |
4161 | 0 | SAMR_ACCESS_CONNECT_TO_SERVER | |
4162 | 0 | SAMR_ACCESS_ENUM_DOMAINS | |
4163 | 0 | SAMR_ACCESS_LOOKUP_DOMAIN, |
4164 | 0 | &connect_handle, |
4165 | 0 | &result); |
4166 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4167 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4168 | 0 | goto out; |
4169 | 0 | } |
4170 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4171 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4172 | 0 | goto out; |
4173 | 0 | } |
4174 | | |
4175 | 0 | init_lsa_String(&domain_name, get_global_sam_name()); |
4176 | |
|
4177 | 0 | status = dcerpc_samr_LookupDomain(b, mem_ctx, |
4178 | 0 | &connect_handle, |
4179 | 0 | &domain_name, |
4180 | 0 | &domain_sid, |
4181 | 0 | &result); |
4182 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4183 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4184 | 0 | goto out; |
4185 | 0 | } |
4186 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4187 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4188 | 0 | goto out; |
4189 | 0 | } |
4190 | | |
4191 | 0 | status = dcerpc_samr_OpenDomain(b, mem_ctx, |
4192 | 0 | &connect_handle, |
4193 | 0 | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, |
4194 | 0 | domain_sid, |
4195 | 0 | &domain_handle, |
4196 | 0 | &result); |
4197 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4198 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4199 | 0 | goto out; |
4200 | 0 | } |
4201 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4202 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4203 | 0 | goto out; |
4204 | 0 | } |
4205 | | |
4206 | 0 | init_lsa_String(&names, UserName); |
4207 | |
|
4208 | 0 | status = dcerpc_samr_LookupNames(b, mem_ctx, |
4209 | 0 | &domain_handle, |
4210 | 0 | 1, |
4211 | 0 | &names, |
4212 | 0 | &rids, |
4213 | 0 | &types, |
4214 | 0 | &result); |
4215 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4216 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4217 | 0 | goto out; |
4218 | 0 | } |
4219 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4220 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4221 | 0 | goto out; |
4222 | 0 | } |
4223 | | |
4224 | 0 | if (rids.count != 1) { |
4225 | 0 | errcode = W_ERROR_V(WERR_NO_SUCH_USER); |
4226 | 0 | goto out; |
4227 | 0 | } |
4228 | 0 | if (rids.count != types.count) { |
4229 | 0 | errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
4230 | 0 | goto out; |
4231 | 0 | } |
4232 | 0 | if (types.ids[0] != SID_NAME_USER) { |
4233 | 0 | errcode = W_ERROR_V(WERR_INVALID_PARAMETER); |
4234 | 0 | goto out; |
4235 | 0 | } |
4236 | | |
4237 | 0 | rid = rids.ids[0]; |
4238 | |
|
4239 | 0 | status = dcerpc_samr_OpenUser(b, mem_ctx, |
4240 | 0 | &domain_handle, |
4241 | 0 | SAMR_USER_ACCESS_GET_LOCALE | |
4242 | 0 | SAMR_USER_ACCESS_GET_LOGONINFO | |
4243 | 0 | SAMR_USER_ACCESS_GET_ATTRIBUTES | |
4244 | 0 | SAMR_USER_ACCESS_GET_GROUPS | |
4245 | 0 | SAMR_USER_ACCESS_GET_GROUP_MEMBERSHIP | |
4246 | 0 | SEC_STD_READ_CONTROL, |
4247 | 0 | rid, |
4248 | 0 | &user_handle, |
4249 | 0 | &result); |
4250 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4251 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4252 | 0 | goto out; |
4253 | 0 | } |
4254 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4255 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4256 | 0 | goto out; |
4257 | 0 | } |
4258 | | |
4259 | 0 | status = dcerpc_samr_QueryUserInfo2(b, mem_ctx, |
4260 | 0 | &user_handle, |
4261 | 0 | UserAllInformation, |
4262 | 0 | &info, |
4263 | 0 | &result); |
4264 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4265 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4266 | 0 | goto out; |
4267 | 0 | } |
4268 | 0 | if (!NT_STATUS_IS_OK(result)) { |
4269 | 0 | errcode = W_ERROR_V(ntstatus_to_werror(result)); |
4270 | 0 | goto out; |
4271 | 0 | } |
4272 | | |
4273 | 0 | memset(p,0,21); |
4274 | 0 | fstrcpy(p+usri11_name,UserName); /* 21 bytes - user name */ |
4275 | |
|
4276 | 0 | if (uLevel > 0) { |
4277 | 0 | SCVAL(p,usri11_pad,0); /* padding - 1 byte */ |
4278 | 0 | *p2 = 0; |
4279 | 0 | } |
4280 | |
|
4281 | 0 | if (uLevel >= 10) { |
4282 | 0 | SIVAL(p,usri11_comment,PTR_DIFF(p2,p)); /* comment */ |
4283 | 0 | strlcpy(p2,"Comment",PTR_DIFF(endp,p2)); |
4284 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4285 | 0 | if (!p2) { |
4286 | 0 | return False; |
4287 | 0 | } |
4288 | | |
4289 | 0 | SIVAL(p,usri11_usr_comment,PTR_DIFF(p2,p)); /* user_comment */ |
4290 | 0 | strlcpy(p2,"UserComment",PTR_DIFF(endp,p2)); |
4291 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4292 | 0 | if (!p2) { |
4293 | 0 | return False; |
4294 | 0 | } |
4295 | | |
4296 | | /* EEK! the cifsrap.txt doesn't have this in!!!! */ |
4297 | 0 | SIVAL(p,usri11_full_name,PTR_DIFF(p2,p)); /* full name */ |
4298 | 0 | strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2)); |
4299 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4300 | 0 | if (!p2) { |
4301 | 0 | return False; |
4302 | 0 | } |
4303 | 0 | } |
4304 | | |
4305 | 0 | if (uLevel == 11) { |
4306 | 0 | const char *homedir = info->info21.home_directory.string; |
4307 | | /* modelled after NTAS 3.51 reply */ |
4308 | 0 | SSVAL(p,usri11_priv, |
4309 | 0 | (get_current_uid(conn) == sec_initial_uid())? |
4310 | 0 | USER_PRIV_ADMIN:USER_PRIV_USER); |
4311 | 0 | SIVAL(p,usri11_auth_flags,AF_OP_PRINT); /* auth flags */ |
4312 | 0 | SIVALS(p,usri11_password_age,-1); /* password age */ |
4313 | 0 | SIVAL(p,usri11_homedir,PTR_DIFF(p2,p)); /* home dir */ |
4314 | 0 | strlcpy(p2, homedir, PTR_DIFF(endp,p2)); |
4315 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4316 | 0 | if (!p2) { |
4317 | 0 | return False; |
4318 | 0 | } |
4319 | 0 | SIVAL(p,usri11_parms,PTR_DIFF(p2,p)); /* parms */ |
4320 | 0 | strlcpy(p2,"",PTR_DIFF(endp,p2)); |
4321 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4322 | 0 | if (!p2) { |
4323 | 0 | return False; |
4324 | 0 | } |
4325 | 0 | SIVAL(p,usri11_last_logon,0); /* last logon */ |
4326 | 0 | SIVAL(p,usri11_last_logoff,0); /* last logoff */ |
4327 | 0 | SSVALS(p,usri11_bad_pw_count,-1); /* bad pw counts */ |
4328 | 0 | SSVALS(p,usri11_num_logons,-1); /* num logons */ |
4329 | 0 | SIVAL(p,usri11_logon_server,PTR_DIFF(p2,p)); /* logon server */ |
4330 | 0 | strlcpy(p2,"\\\\*",PTR_DIFF(endp,p2)); |
4331 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4332 | 0 | if (!p2) { |
4333 | 0 | return False; |
4334 | 0 | } |
4335 | 0 | SSVAL(p,usri11_country_code,0); /* country code */ |
4336 | |
|
4337 | 0 | SIVAL(p,usri11_workstations,PTR_DIFF(p2,p)); /* workstations */ |
4338 | 0 | strlcpy(p2,"",PTR_DIFF(endp,p2)); |
4339 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4340 | 0 | if (!p2) { |
4341 | 0 | return False; |
4342 | 0 | } |
4343 | | |
4344 | 0 | SIVALS(p,usri11_max_storage,-1); /* max storage */ |
4345 | 0 | SSVAL(p,usri11_units_per_week,168); /* units per week */ |
4346 | 0 | SIVAL(p,usri11_logon_hours,PTR_DIFF(p2,p)); /* logon hours */ |
4347 | | |
4348 | | /* a simple way to get logon hours at all times. */ |
4349 | 0 | memset(p2,0xff,21); |
4350 | 0 | SCVAL(p2,21,0); /* fix zero termination */ |
4351 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4352 | 0 | if (!p2) { |
4353 | 0 | return False; |
4354 | 0 | } |
4355 | | |
4356 | 0 | SSVAL(p,usri11_code_page,0); /* code page */ |
4357 | 0 | } |
4358 | | |
4359 | 0 | if (uLevel == 1 || uLevel == 2) { |
4360 | 0 | memset(p+22,' ',16); /* password */ |
4361 | 0 | SIVALS(p,38,-1); /* password age */ |
4362 | 0 | SSVAL(p,42, |
4363 | 0 | (get_current_uid(conn) == sec_initial_uid())? |
4364 | 0 | USER_PRIV_ADMIN:USER_PRIV_USER); |
4365 | 0 | SIVAL(p,44,PTR_DIFF(p2,*rdata)); /* home dir */ |
4366 | 0 | strlcpy(p2, info->info21.home_directory.string, |
4367 | 0 | PTR_DIFF(endp,p2)); |
4368 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4369 | 0 | if (!p2) { |
4370 | 0 | return False; |
4371 | 0 | } |
4372 | 0 | SIVAL(p,48,PTR_DIFF(p2,*rdata)); /* comment */ |
4373 | 0 | *p2++ = 0; |
4374 | 0 | SSVAL(p,52,0); /* flags */ |
4375 | 0 | SIVAL(p,54,PTR_DIFF(p2,*rdata)); /* script_path */ |
4376 | 0 | strlcpy(p2, info->info21.logon_script.string, |
4377 | 0 | PTR_DIFF(endp,p2)); |
4378 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4379 | 0 | if (!p2) { |
4380 | 0 | return False; |
4381 | 0 | } |
4382 | 0 | if (uLevel == 2) { |
4383 | 0 | SIVAL(p,58,0); /* auth_flags */ |
4384 | 0 | SIVAL(p,62,PTR_DIFF(p2,*rdata)); /* full_name */ |
4385 | 0 | strlcpy(p2,info->info21.full_name.string,PTR_DIFF(endp,p2)); |
4386 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4387 | 0 | if (!p2) { |
4388 | 0 | return False; |
4389 | 0 | } |
4390 | 0 | SIVAL(p,66,0); /* urs_comment */ |
4391 | 0 | SIVAL(p,70,PTR_DIFF(p2,*rdata)); /* parms */ |
4392 | 0 | strlcpy(p2,"",PTR_DIFF(endp,p2)); |
4393 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4394 | 0 | if (!p2) { |
4395 | 0 | return False; |
4396 | 0 | } |
4397 | 0 | SIVAL(p,74,0); /* workstations */ |
4398 | 0 | SIVAL(p,78,0); /* last_logon */ |
4399 | 0 | SIVAL(p,82,0); /* last_logoff */ |
4400 | 0 | SIVALS(p,86,-1); /* acct_expires */ |
4401 | 0 | SIVALS(p,90,-1); /* max_storage */ |
4402 | 0 | SSVAL(p,94,168); /* units_per_week */ |
4403 | 0 | SIVAL(p,96,PTR_DIFF(p2,*rdata)); /* logon_hours */ |
4404 | 0 | memset(p2,-1,21); |
4405 | 0 | p2 += 21; |
4406 | 0 | SSVALS(p,100,-1); /* bad_pw_count */ |
4407 | 0 | SSVALS(p,102,-1); /* num_logons */ |
4408 | 0 | SIVAL(p,104,PTR_DIFF(p2,*rdata)); /* logon_server */ |
4409 | 0 | { |
4410 | 0 | TALLOC_CTX *ctx = talloc_tos(); |
4411 | 0 | int space_rem = *rdata_len - (p2 - *rdata); |
4412 | 0 | char *tmp; |
4413 | |
|
4414 | 0 | if (space_rem <= 0) { |
4415 | 0 | return false; |
4416 | 0 | } |
4417 | 0 | tmp = talloc_strdup(ctx, "\\\\%L"); |
4418 | 0 | if (!tmp) { |
4419 | 0 | return false; |
4420 | 0 | } |
4421 | 0 | tmp = talloc_sub_basic(ctx, |
4422 | 0 | "", |
4423 | 0 | "", |
4424 | 0 | tmp); |
4425 | 0 | if (!tmp) { |
4426 | 0 | return false; |
4427 | 0 | } |
4428 | | |
4429 | 0 | push_ascii(p2, |
4430 | 0 | tmp, |
4431 | 0 | space_rem, |
4432 | 0 | STR_TERMINATE); |
4433 | 0 | } |
4434 | 0 | p2 = skip_string(*rdata,*rdata_len,p2); |
4435 | 0 | if (!p2) { |
4436 | 0 | return False; |
4437 | 0 | } |
4438 | 0 | SSVAL(p,108,49); /* country_code */ |
4439 | 0 | SSVAL(p,110,860); /* code page */ |
4440 | 0 | } |
4441 | 0 | } |
4442 | | |
4443 | 0 | errcode = NERR_Success; |
4444 | |
|
4445 | 0 | out: |
4446 | 0 | *rdata_len = PTR_DIFF(p2,*rdata); |
4447 | |
|
4448 | 0 | if (b && is_valid_policy_hnd(&user_handle)) { |
4449 | 0 | dcerpc_samr_Close(b, mem_ctx, &user_handle, &result); |
4450 | 0 | } |
4451 | 0 | if (b && is_valid_policy_hnd(&domain_handle)) { |
4452 | 0 | dcerpc_samr_Close(b, mem_ctx, &domain_handle, &result); |
4453 | 0 | } |
4454 | 0 | if (b && is_valid_policy_hnd(&connect_handle)) { |
4455 | 0 | dcerpc_samr_Close(b, mem_ctx, &connect_handle, &result); |
4456 | 0 | } |
4457 | |
|
4458 | 0 | SSVAL(*rparam,0,errcode); |
4459 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
4460 | 0 | SSVAL(*rparam,4,*rdata_len); /* is this right?? */ |
4461 | |
|
4462 | 0 | return(True); |
4463 | 0 | } |
4464 | | |
4465 | | static bool api_WWkstaUserLogon(struct smbd_server_connection *sconn, |
4466 | | connection_struct *conn,uint64_t vuid, |
4467 | | char *param, int tpscnt, |
4468 | | char *data, int tdscnt, |
4469 | | int mdrcnt,int mprcnt, |
4470 | | char **rdata,char **rparam, |
4471 | | int *rdata_len,int *rparam_len) |
4472 | 0 | { |
4473 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4474 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4475 | 0 | char *p = skip_string(param,tpscnt,str2); |
4476 | 0 | int uLevel; |
4477 | 0 | struct pack_desc desc; |
4478 | 0 | char* name; |
4479 | 0 | struct auth_session_info *si = NULL; |
4480 | 0 | NTSTATUS status; |
4481 | |
|
4482 | 0 | status = smbXsrv_session_info_lookup(conn->sconn->client, |
4483 | 0 | vuid, |
4484 | 0 | &si); |
4485 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4486 | 0 | return false; |
4487 | 0 | } |
4488 | | |
4489 | 0 | if (!str1 || !str2 || !p) { |
4490 | 0 | return False; |
4491 | 0 | } |
4492 | | |
4493 | 0 | DBG_INFO("Username of UID %ju is %s\n", |
4494 | 0 | (uintmax_t)si->unix_token->uid, |
4495 | 0 | si->unix_info->unix_name); |
4496 | |
|
4497 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
4498 | 0 | name = get_safe_str_ptr(param,tpscnt,p,2); |
4499 | 0 | if (!name) { |
4500 | 0 | return False; |
4501 | 0 | } |
4502 | | |
4503 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
4504 | |
|
4505 | 0 | DEBUG(3,("WWkstaUserLogon uLevel=%d name=%s\n",uLevel,name)); |
4506 | | |
4507 | | /* check it's a supported variant */ |
4508 | 0 | if (strcmp(str1,"OOWb54WrLh") != 0) { |
4509 | 0 | return False; |
4510 | 0 | } |
4511 | 0 | if (uLevel != 1 || strcmp(str2,"WB21BWDWWDDDDDDDzzzD") != 0) { |
4512 | 0 | return False; |
4513 | 0 | } |
4514 | 0 | if (mdrcnt > 0) { |
4515 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
4516 | 0 | if (!*rdata) { |
4517 | 0 | return False; |
4518 | 0 | } |
4519 | 0 | } |
4520 | | |
4521 | 0 | desc.base = *rdata; |
4522 | 0 | desc.buflen = mdrcnt; |
4523 | 0 | desc.subformat = NULL; |
4524 | 0 | desc.format = str2; |
4525 | |
|
4526 | 0 | if (init_package(&desc,1,0)) { |
4527 | 0 | PACKI(&desc,"W",0); /* code */ |
4528 | 0 | PACKS(&desc,"B21",name); /* eff. name */ |
4529 | 0 | PACKS(&desc,"B",""); /* pad */ |
4530 | 0 | PACKI(&desc,"W", |
4531 | 0 | (get_current_uid(conn) == sec_initial_uid())? |
4532 | 0 | USER_PRIV_ADMIN:USER_PRIV_USER); |
4533 | 0 | PACKI(&desc,"D",0); /* auth flags XXX */ |
4534 | 0 | PACKI(&desc,"W",0); /* num logons */ |
4535 | 0 | PACKI(&desc,"W",0); /* bad pw count */ |
4536 | 0 | PACKI(&desc,"D",0); /* last logon */ |
4537 | 0 | PACKI(&desc,"D",-1); /* last logoff */ |
4538 | 0 | PACKI(&desc,"D",-1); /* logoff time */ |
4539 | 0 | PACKI(&desc,"D",-1); /* kickoff time */ |
4540 | 0 | PACKI(&desc,"D",0); /* password age */ |
4541 | 0 | PACKI(&desc,"D",0); /* password can change */ |
4542 | 0 | PACKI(&desc,"D",-1); /* password must change */ |
4543 | |
|
4544 | 0 | { |
4545 | 0 | fstring mypath; |
4546 | 0 | fstrcpy(mypath,"\\\\"); |
4547 | 0 | fstrcat(mypath,get_local_machine_name()); |
4548 | 0 | if (!strupper_m(mypath)) { |
4549 | 0 | return false; |
4550 | 0 | } |
4551 | 0 | PACKS(&desc,"z",mypath); /* computer */ |
4552 | 0 | } |
4553 | | |
4554 | 0 | PACKS(&desc,"z",lp_workgroup());/* domain */ |
4555 | 0 | PACKS(&desc,"z", si->info->logon_script); /* script path */ |
4556 | 0 | PACKI(&desc,"D",0x00000000); /* reserved */ |
4557 | 0 | } |
4558 | | |
4559 | 0 | *rdata_len = desc.usedlen; |
4560 | 0 | *rparam_len = 6; |
4561 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
4562 | 0 | if (!*rparam) { |
4563 | 0 | return False; |
4564 | 0 | } |
4565 | 0 | SSVALS(*rparam,0,desc.errcode); |
4566 | 0 | SSVAL(*rparam,2,0); |
4567 | 0 | SSVAL(*rparam,4,desc.neededlen); |
4568 | |
|
4569 | 0 | DEBUG(4,("WWkstaUserLogon: errorcode %d\n",desc.errcode)); |
4570 | |
|
4571 | 0 | return True; |
4572 | 0 | } |
4573 | | |
4574 | | /**************************************************************************** |
4575 | | api_WAccessGetUserPerms |
4576 | | ****************************************************************************/ |
4577 | | |
4578 | | static bool api_WAccessGetUserPerms(struct smbd_server_connection *sconn, |
4579 | | connection_struct *conn,uint64_t vuid, |
4580 | | char *param, int tpscnt, |
4581 | | char *data, int tdscnt, |
4582 | | int mdrcnt,int mprcnt, |
4583 | | char **rdata,char **rparam, |
4584 | | int *rdata_len,int *rparam_len) |
4585 | 0 | { |
4586 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4587 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4588 | 0 | char *user = skip_string(param,tpscnt,str2); |
4589 | 0 | char *resource = skip_string(param,tpscnt,user); |
4590 | |
|
4591 | 0 | if (!str1 || !str2 || !user || !resource) { |
4592 | 0 | return False; |
4593 | 0 | } |
4594 | | |
4595 | 0 | if (skip_string(param,tpscnt,resource) == NULL) { |
4596 | 0 | return False; |
4597 | 0 | } |
4598 | 0 | DEBUG(3,("WAccessGetUserPerms user=%s resource=%s\n",user,resource)); |
4599 | | |
4600 | | /* check it's a supported variant */ |
4601 | 0 | if (strcmp(str1,"zzh") != 0) { |
4602 | 0 | return False; |
4603 | 0 | } |
4604 | 0 | if (strcmp(str2,"") != 0) { |
4605 | 0 | return False; |
4606 | 0 | } |
4607 | | |
4608 | 0 | *rparam_len = 6; |
4609 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
4610 | 0 | if (!*rparam) { |
4611 | 0 | return False; |
4612 | 0 | } |
4613 | 0 | SSVALS(*rparam,0,0); /* errorcode */ |
4614 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
4615 | 0 | SSVAL(*rparam,4,0x7f); /* permission flags */ |
4616 | |
|
4617 | 0 | return True; |
4618 | 0 | } |
4619 | | |
4620 | | /**************************************************************************** |
4621 | | api_WPrintJobEnumerate |
4622 | | ****************************************************************************/ |
4623 | | |
4624 | | static bool api_WPrintJobGetInfo(struct smbd_server_connection *sconn, |
4625 | | connection_struct *conn, uint64_t vuid, |
4626 | | char *param, int tpscnt, |
4627 | | char *data, int tdscnt, |
4628 | | int mdrcnt,int mprcnt, |
4629 | | char **rdata,char **rparam, |
4630 | | int *rdata_len,int *rparam_len) |
4631 | 0 | { |
4632 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4633 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4634 | 0 | char *p = skip_string(param,tpscnt,str2); |
4635 | 0 | int uLevel; |
4636 | 0 | fstring sharename; |
4637 | 0 | uint32_t jobid; |
4638 | 0 | struct pack_desc desc; |
4639 | 0 | char *tmpdata=NULL; |
4640 | |
|
4641 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
4642 | 0 | WERROR werr; |
4643 | 0 | NTSTATUS status; |
4644 | 0 | struct rpc_pipe_client *cli = NULL; |
4645 | 0 | struct dcerpc_binding_handle *b = NULL; |
4646 | 0 | struct policy_handle handle; |
4647 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
4648 | 0 | union spoolss_JobInfo info; |
4649 | |
|
4650 | 0 | if (!str1 || !str2 || !p) { |
4651 | 0 | return False; |
4652 | 0 | } |
4653 | | |
4654 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,2,-1); |
4655 | |
|
4656 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
4657 | 0 | memset((char *)&status,'\0',sizeof(status)); |
4658 | |
|
4659 | 0 | DEBUG(3,("WPrintJobGetInfo uLevel=%d uJobId=0x%X\n",uLevel,SVAL(p,0))); |
4660 | | |
4661 | | /* check it's a supported variant */ |
4662 | 0 | if (strcmp(str1,"WWrLh") != 0) { |
4663 | 0 | return False; |
4664 | 0 | } |
4665 | 0 | if (!check_printjob_info(&desc,uLevel,str2)) { |
4666 | 0 | return False; |
4667 | 0 | } |
4668 | | |
4669 | 0 | if(!rap_to_pjobid(SVAL(p,0), sharename, &jobid)) { |
4670 | 0 | return False; |
4671 | 0 | } |
4672 | | |
4673 | 0 | ZERO_STRUCT(handle); |
4674 | |
|
4675 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
4676 | 0 | &ndr_table_spoolss, |
4677 | 0 | conn->session_info, |
4678 | 0 | conn->sconn->remote_address, |
4679 | 0 | conn->sconn->local_address, |
4680 | 0 | conn->sconn->msg_ctx, |
4681 | 0 | &cli); |
4682 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4683 | 0 | DEBUG(0,("api_WPrintJobGetInfo: could not connect to spoolss: %s\n", |
4684 | 0 | nt_errstr(status))); |
4685 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4686 | 0 | goto out; |
4687 | 0 | } |
4688 | 0 | b = cli->binding_handle; |
4689 | |
|
4690 | 0 | ZERO_STRUCT(devmode_ctr); |
4691 | |
|
4692 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
4693 | 0 | sharename, |
4694 | 0 | "RAW", |
4695 | 0 | devmode_ctr, |
4696 | 0 | PRINTER_ACCESS_USE, |
4697 | 0 | &handle, |
4698 | 0 | &werr); |
4699 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4700 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4701 | 0 | goto out; |
4702 | 0 | } |
4703 | 0 | if (!W_ERROR_IS_OK(werr)) { |
4704 | 0 | desc.errcode = W_ERROR_V(werr); |
4705 | 0 | goto out; |
4706 | 0 | } |
4707 | | |
4708 | 0 | werr = rpccli_spoolss_getjob(cli, mem_ctx, |
4709 | 0 | &handle, |
4710 | 0 | jobid, |
4711 | 0 | 2, /* level */ |
4712 | 0 | 0, /* offered */ |
4713 | 0 | &info); |
4714 | 0 | if (!W_ERROR_IS_OK(werr)) { |
4715 | 0 | desc.errcode = W_ERROR_V(werr); |
4716 | 0 | goto out; |
4717 | 0 | } |
4718 | | |
4719 | 0 | if (mdrcnt > 0) { |
4720 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
4721 | 0 | if (!*rdata) { |
4722 | 0 | return False; |
4723 | 0 | } |
4724 | 0 | desc.base = *rdata; |
4725 | 0 | desc.buflen = mdrcnt; |
4726 | 0 | } else { |
4727 | | /* |
4728 | | * Don't return data but need to get correct length |
4729 | | * init_package will return wrong size if buflen=0 |
4730 | | */ |
4731 | 0 | desc.buflen = getlen(desc.format); |
4732 | 0 | desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); |
4733 | 0 | } |
4734 | | |
4735 | 0 | if (init_package(&desc,1,0)) { |
4736 | 0 | fill_spoolss_printjob_info(uLevel, &desc, &info.info2, info.info2.position); |
4737 | 0 | *rdata_len = desc.usedlen; |
4738 | 0 | } else { |
4739 | 0 | desc.errcode = NERR_JobNotFound; |
4740 | 0 | *rdata_len = 0; |
4741 | 0 | } |
4742 | 0 | out: |
4743 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
4744 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
4745 | 0 | } |
4746 | |
|
4747 | 0 | *rparam_len = 6; |
4748 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
4749 | 0 | if (!*rparam) { |
4750 | 0 | return False; |
4751 | 0 | } |
4752 | 0 | SSVALS(*rparam,0,desc.errcode); |
4753 | 0 | SSVAL(*rparam,2,0); |
4754 | 0 | SSVAL(*rparam,4,desc.neededlen); |
4755 | |
|
4756 | 0 | SAFE_FREE(tmpdata); |
4757 | |
|
4758 | 0 | DEBUG(4,("WPrintJobGetInfo: errorcode %d\n",desc.errcode)); |
4759 | |
|
4760 | 0 | return True; |
4761 | 0 | } |
4762 | | |
4763 | | static bool api_WPrintJobEnumerate(struct smbd_server_connection *sconn, |
4764 | | connection_struct *conn, uint64_t vuid, |
4765 | | char *param, int tpscnt, |
4766 | | char *data, int tdscnt, |
4767 | | int mdrcnt,int mprcnt, |
4768 | | char **rdata,char **rparam, |
4769 | | int *rdata_len,int *rparam_len) |
4770 | 0 | { |
4771 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4772 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4773 | 0 | char *p = skip_string(param,tpscnt,str2); |
4774 | 0 | char *name = p; |
4775 | 0 | int uLevel; |
4776 | 0 | int i, succnt=0; |
4777 | 0 | struct pack_desc desc; |
4778 | |
|
4779 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
4780 | 0 | WERROR werr; |
4781 | 0 | NTSTATUS status; |
4782 | 0 | struct rpc_pipe_client *cli = NULL; |
4783 | 0 | struct dcerpc_binding_handle *b = NULL; |
4784 | 0 | struct policy_handle handle; |
4785 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
4786 | 0 | uint32_t count = 0; |
4787 | 0 | union spoolss_JobInfo *info; |
4788 | |
|
4789 | 0 | if (!str1 || !str2 || !p) { |
4790 | 0 | return False; |
4791 | 0 | } |
4792 | | |
4793 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
4794 | |
|
4795 | 0 | p = skip_string(param,tpscnt,p); |
4796 | 0 | if (!p) { |
4797 | 0 | return False; |
4798 | 0 | } |
4799 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
4800 | |
|
4801 | 0 | DEBUG(3,("WPrintJobEnumerate uLevel=%d name=%s\n",uLevel,name)); |
4802 | | |
4803 | | /* check it's a supported variant */ |
4804 | 0 | if (strcmp(str1,"zWrLeh") != 0) { |
4805 | 0 | return False; |
4806 | 0 | } |
4807 | | |
4808 | 0 | if (uLevel > 2) { |
4809 | 0 | return False; /* defined only for uLevel 0,1,2 */ |
4810 | 0 | } |
4811 | | |
4812 | 0 | if (!check_printjob_info(&desc,uLevel,str2)) { |
4813 | 0 | return False; |
4814 | 0 | } |
4815 | | |
4816 | 0 | ZERO_STRUCT(handle); |
4817 | |
|
4818 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
4819 | 0 | &ndr_table_spoolss, |
4820 | 0 | conn->session_info, |
4821 | 0 | conn->sconn->remote_address, |
4822 | 0 | conn->sconn->local_address, |
4823 | 0 | conn->sconn->msg_ctx, |
4824 | 0 | &cli); |
4825 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4826 | 0 | DEBUG(0,("api_WPrintJobEnumerate: could not connect to spoolss: %s\n", |
4827 | 0 | nt_errstr(status))); |
4828 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4829 | 0 | goto out; |
4830 | 0 | } |
4831 | 0 | b = cli->binding_handle; |
4832 | |
|
4833 | 0 | ZERO_STRUCT(devmode_ctr); |
4834 | |
|
4835 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
4836 | 0 | name, |
4837 | 0 | NULL, |
4838 | 0 | devmode_ctr, |
4839 | 0 | PRINTER_ACCESS_USE, |
4840 | 0 | &handle, |
4841 | 0 | &werr); |
4842 | 0 | if (!NT_STATUS_IS_OK(status)) { |
4843 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
4844 | 0 | goto out; |
4845 | 0 | } |
4846 | 0 | if (!W_ERROR_IS_OK(werr)) { |
4847 | 0 | desc.errcode = W_ERROR_V(werr); |
4848 | 0 | goto out; |
4849 | 0 | } |
4850 | | |
4851 | 0 | werr = rpccli_spoolss_enumjobs(cli, mem_ctx, |
4852 | 0 | &handle, |
4853 | 0 | 0, /* firstjob */ |
4854 | 0 | 0xff, /* numjobs */ |
4855 | 0 | 2, /* level */ |
4856 | 0 | 0, /* offered */ |
4857 | 0 | &count, |
4858 | 0 | &info); |
4859 | 0 | if (!W_ERROR_IS_OK(werr)) { |
4860 | 0 | desc.errcode = W_ERROR_V(werr); |
4861 | 0 | goto out; |
4862 | 0 | } |
4863 | | |
4864 | 0 | if (mdrcnt > 0) { |
4865 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
4866 | 0 | if (!*rdata) { |
4867 | 0 | return False; |
4868 | 0 | } |
4869 | 0 | } |
4870 | 0 | desc.base = *rdata; |
4871 | 0 | desc.buflen = mdrcnt; |
4872 | |
|
4873 | 0 | if (init_package(&desc,count,0)) { |
4874 | 0 | succnt = 0; |
4875 | 0 | for (i = 0; i < count; i++) { |
4876 | 0 | fill_spoolss_printjob_info(uLevel, &desc, &info[i].info2, i); |
4877 | 0 | if (desc.errcode == NERR_Success) { |
4878 | 0 | succnt = i+1; |
4879 | 0 | } |
4880 | 0 | } |
4881 | 0 | } |
4882 | 0 | out: |
4883 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
4884 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
4885 | 0 | } |
4886 | |
|
4887 | 0 | *rdata_len = desc.usedlen; |
4888 | |
|
4889 | 0 | *rparam_len = 8; |
4890 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
4891 | 0 | if (!*rparam) { |
4892 | 0 | return False; |
4893 | 0 | } |
4894 | 0 | SSVALS(*rparam,0,desc.errcode); |
4895 | 0 | SSVAL(*rparam,2,0); |
4896 | 0 | SSVAL(*rparam,4,succnt); |
4897 | 0 | SSVAL(*rparam,6,count); |
4898 | |
|
4899 | 0 | DEBUG(4,("WPrintJobEnumerate: errorcode %d\n",desc.errcode)); |
4900 | |
|
4901 | 0 | return True; |
4902 | 0 | } |
4903 | | |
4904 | | static int check_printdest_info(struct pack_desc* desc, |
4905 | | int uLevel, char* id) |
4906 | 0 | { |
4907 | 0 | desc->subformat = NULL; |
4908 | 0 | switch( uLevel ) { |
4909 | 0 | case 0: |
4910 | 0 | desc->format = "B9"; |
4911 | 0 | break; |
4912 | 0 | case 1: |
4913 | 0 | desc->format = "B9B21WWzW"; |
4914 | 0 | break; |
4915 | 0 | case 2: |
4916 | 0 | desc->format = "z"; |
4917 | 0 | break; |
4918 | 0 | case 3: |
4919 | 0 | desc->format = "zzzWWzzzWW"; |
4920 | 0 | break; |
4921 | 0 | default: |
4922 | 0 | DEBUG(0,("check_printdest_info: invalid level %d\n", |
4923 | 0 | uLevel)); |
4924 | 0 | return False; |
4925 | 0 | } |
4926 | 0 | if (id == NULL || strcmp(desc->format,id) != 0) { |
4927 | 0 | DEBUG(0,("check_printdest_info: invalid string %s\n", |
4928 | 0 | id ? id : "<NULL>" )); |
4929 | 0 | return False; |
4930 | 0 | } |
4931 | 0 | return True; |
4932 | 0 | } |
4933 | | |
4934 | | static void fill_printdest_info(struct spoolss_PrinterInfo2 *info2, int uLevel, |
4935 | | struct pack_desc* desc) |
4936 | 0 | { |
4937 | 0 | char buf[100]; |
4938 | |
|
4939 | 0 | strncpy(buf, info2->printername, sizeof(buf)-1); |
4940 | 0 | buf[sizeof(buf)-1] = 0; |
4941 | 0 | (void)strupper_m(buf); |
4942 | |
|
4943 | 0 | if (uLevel <= 1) { |
4944 | 0 | PACKS(desc,"B9",buf); /* szName */ |
4945 | 0 | if (uLevel == 1) { |
4946 | 0 | PACKS(desc,"B21",""); /* szUserName */ |
4947 | 0 | PACKI(desc,"W",0); /* uJobId */ |
4948 | 0 | PACKI(desc,"W",0); /* fsStatus */ |
4949 | 0 | PACKS(desc,"z",""); /* pszStatus */ |
4950 | 0 | PACKI(desc,"W",0); /* time */ |
4951 | 0 | } |
4952 | 0 | } |
4953 | |
|
4954 | 0 | if (uLevel == 2 || uLevel == 3) { |
4955 | 0 | PACKS(desc,"z",buf); /* pszPrinterName */ |
4956 | 0 | if (uLevel == 3) { |
4957 | 0 | PACKS(desc,"z",""); /* pszUserName */ |
4958 | 0 | PACKS(desc,"z",""); /* pszLogAddr */ |
4959 | 0 | PACKI(desc,"W",0); /* uJobId */ |
4960 | 0 | PACKI(desc,"W",0); /* fsStatus */ |
4961 | 0 | PACKS(desc,"z",""); /* pszStatus */ |
4962 | 0 | PACKS(desc,"z",""); /* pszComment */ |
4963 | 0 | PACKS(desc,"z","NULL"); /* pszDrivers */ |
4964 | 0 | PACKI(desc,"W",0); /* time */ |
4965 | 0 | PACKI(desc,"W",0); /* pad1 */ |
4966 | 0 | } |
4967 | 0 | } |
4968 | 0 | } |
4969 | | |
4970 | | static bool api_WPrintDestGetInfo(struct smbd_server_connection *sconn, |
4971 | | connection_struct *conn, uint64_t vuid, |
4972 | | char *param, int tpscnt, |
4973 | | char *data, int tdscnt, |
4974 | | int mdrcnt,int mprcnt, |
4975 | | char **rdata,char **rparam, |
4976 | | int *rdata_len,int *rparam_len) |
4977 | 0 | { |
4978 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
4979 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
4980 | 0 | char *p = skip_string(param,tpscnt,str2); |
4981 | 0 | char* PrinterName = p; |
4982 | 0 | int uLevel; |
4983 | 0 | struct pack_desc desc; |
4984 | 0 | char *tmpdata=NULL; |
4985 | |
|
4986 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
4987 | 0 | WERROR werr; |
4988 | 0 | NTSTATUS status; |
4989 | 0 | struct rpc_pipe_client *cli = NULL; |
4990 | 0 | struct dcerpc_binding_handle *b = NULL; |
4991 | 0 | struct policy_handle handle; |
4992 | 0 | struct spoolss_DevmodeContainer devmode_ctr; |
4993 | 0 | union spoolss_PrinterInfo info; |
4994 | |
|
4995 | 0 | if (!str1 || !str2 || !p) { |
4996 | 0 | return False; |
4997 | 0 | } |
4998 | | |
4999 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5000 | |
|
5001 | 0 | p = skip_string(param,tpscnt,p); |
5002 | 0 | if (!p) { |
5003 | 0 | return False; |
5004 | 0 | } |
5005 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5006 | |
|
5007 | 0 | DEBUG(3,("WPrintDestGetInfo uLevel=%d PrinterName=%s\n",uLevel,PrinterName)); |
5008 | | |
5009 | | /* check it's a supported variant */ |
5010 | 0 | if (strcmp(str1,"zWrLh") != 0) { |
5011 | 0 | return False; |
5012 | 0 | } |
5013 | 0 | if (!check_printdest_info(&desc,uLevel,str2)) { |
5014 | 0 | return False; |
5015 | 0 | } |
5016 | | |
5017 | 0 | ZERO_STRUCT(handle); |
5018 | |
|
5019 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
5020 | 0 | &ndr_table_spoolss, |
5021 | 0 | conn->session_info, |
5022 | 0 | conn->sconn->remote_address, |
5023 | 0 | conn->sconn->local_address, |
5024 | 0 | conn->sconn->msg_ctx, |
5025 | 0 | &cli); |
5026 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5027 | 0 | DEBUG(0,("api_WPrintDestGetInfo: could not connect to spoolss: %s\n", |
5028 | 0 | nt_errstr(status))); |
5029 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
5030 | 0 | goto out; |
5031 | 0 | } |
5032 | 0 | b = cli->binding_handle; |
5033 | |
|
5034 | 0 | ZERO_STRUCT(devmode_ctr); |
5035 | |
|
5036 | 0 | status = dcerpc_spoolss_OpenPrinter(b, mem_ctx, |
5037 | 0 | PrinterName, |
5038 | 0 | NULL, |
5039 | 0 | devmode_ctr, |
5040 | 0 | PRINTER_ACCESS_USE, |
5041 | 0 | &handle, |
5042 | 0 | &werr); |
5043 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5044 | 0 | *rdata_len = 0; |
5045 | 0 | desc.errcode = NERR_DestNotFound; |
5046 | 0 | desc.neededlen = 0; |
5047 | 0 | goto out; |
5048 | 0 | } |
5049 | 0 | if (!W_ERROR_IS_OK(werr)) { |
5050 | 0 | *rdata_len = 0; |
5051 | 0 | desc.errcode = NERR_DestNotFound; |
5052 | 0 | desc.neededlen = 0; |
5053 | 0 | goto out; |
5054 | 0 | } |
5055 | | |
5056 | 0 | werr = rpccli_spoolss_getprinter(cli, mem_ctx, |
5057 | 0 | &handle, |
5058 | 0 | 2, |
5059 | 0 | 0, |
5060 | 0 | &info); |
5061 | 0 | if (!W_ERROR_IS_OK(werr)) { |
5062 | 0 | *rdata_len = 0; |
5063 | 0 | desc.errcode = NERR_DestNotFound; |
5064 | 0 | desc.neededlen = 0; |
5065 | 0 | goto out; |
5066 | 0 | } |
5067 | | |
5068 | 0 | if (mdrcnt > 0) { |
5069 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5070 | 0 | if (!*rdata) { |
5071 | 0 | return False; |
5072 | 0 | } |
5073 | 0 | desc.base = *rdata; |
5074 | 0 | desc.buflen = mdrcnt; |
5075 | 0 | } else { |
5076 | | /* |
5077 | | * Don't return data but need to get correct length |
5078 | | * init_package will return wrong size if buflen=0 |
5079 | | */ |
5080 | 0 | desc.buflen = getlen(desc.format); |
5081 | 0 | desc.base = tmpdata = (char *)SMB_MALLOC( desc.buflen ); |
5082 | 0 | } |
5083 | 0 | if (init_package(&desc,1,0)) { |
5084 | 0 | fill_printdest_info(&info.info2, uLevel,&desc); |
5085 | 0 | } |
5086 | |
|
5087 | 0 | out: |
5088 | 0 | if (b && is_valid_policy_hnd(&handle)) { |
5089 | 0 | dcerpc_spoolss_ClosePrinter(b, mem_ctx, &handle, &werr); |
5090 | 0 | } |
5091 | |
|
5092 | 0 | *rdata_len = desc.usedlen; |
5093 | |
|
5094 | 0 | *rparam_len = 6; |
5095 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5096 | 0 | if (!*rparam) { |
5097 | 0 | return False; |
5098 | 0 | } |
5099 | 0 | SSVALS(*rparam,0,desc.errcode); |
5100 | 0 | SSVAL(*rparam,2,0); |
5101 | 0 | SSVAL(*rparam,4,desc.neededlen); |
5102 | |
|
5103 | 0 | DEBUG(4,("WPrintDestGetInfo: errorcode %d\n",desc.errcode)); |
5104 | 0 | SAFE_FREE(tmpdata); |
5105 | |
|
5106 | 0 | return True; |
5107 | 0 | } |
5108 | | |
5109 | | static bool api_WPrintDestEnum(struct smbd_server_connection *sconn, |
5110 | | connection_struct *conn, uint64_t vuid, |
5111 | | char *param, int tpscnt, |
5112 | | char *data, int tdscnt, |
5113 | | int mdrcnt,int mprcnt, |
5114 | | char **rdata,char **rparam, |
5115 | | int *rdata_len,int *rparam_len) |
5116 | 0 | { |
5117 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
5118 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
5119 | 0 | char *p = skip_string(param,tpscnt,str2); |
5120 | 0 | int uLevel; |
5121 | 0 | int queuecnt; |
5122 | 0 | int i, n, succnt=0; |
5123 | 0 | struct pack_desc desc; |
5124 | |
|
5125 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
5126 | 0 | WERROR werr; |
5127 | 0 | NTSTATUS status; |
5128 | 0 | struct rpc_pipe_client *cli = NULL; |
5129 | 0 | union spoolss_PrinterInfo *info; |
5130 | 0 | uint32_t count; |
5131 | |
|
5132 | 0 | if (!str1 || !str2 || !p) { |
5133 | 0 | return False; |
5134 | 0 | } |
5135 | | |
5136 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5137 | |
|
5138 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5139 | |
|
5140 | 0 | DEBUG(3,("WPrintDestEnum uLevel=%d\n",uLevel)); |
5141 | | |
5142 | | /* check it's a supported variant */ |
5143 | 0 | if (strcmp(str1,"WrLeh") != 0) { |
5144 | 0 | return False; |
5145 | 0 | } |
5146 | 0 | if (!check_printdest_info(&desc,uLevel,str2)) { |
5147 | 0 | return False; |
5148 | 0 | } |
5149 | | |
5150 | 0 | queuecnt = 0; |
5151 | |
|
5152 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
5153 | 0 | &ndr_table_spoolss, |
5154 | 0 | conn->session_info, |
5155 | 0 | conn->sconn->remote_address, |
5156 | 0 | conn->sconn->local_address, |
5157 | 0 | conn->sconn->msg_ctx, |
5158 | 0 | &cli); |
5159 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5160 | 0 | DEBUG(0,("api_WPrintDestEnum: could not connect to spoolss: %s\n", |
5161 | 0 | nt_errstr(status))); |
5162 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
5163 | 0 | goto out; |
5164 | 0 | } |
5165 | | |
5166 | 0 | werr = rpccli_spoolss_enumprinters(cli, mem_ctx, |
5167 | 0 | PRINTER_ENUM_LOCAL, |
5168 | 0 | cli->srv_name_slash, |
5169 | 0 | 2, |
5170 | 0 | 0, |
5171 | 0 | &count, |
5172 | 0 | &info); |
5173 | 0 | if (!W_ERROR_IS_OK(werr)) { |
5174 | 0 | desc.errcode = W_ERROR_V(werr); |
5175 | 0 | *rdata_len = 0; |
5176 | 0 | desc.errcode = NERR_DestNotFound; |
5177 | 0 | desc.neededlen = 0; |
5178 | 0 | goto out; |
5179 | 0 | } |
5180 | | |
5181 | 0 | queuecnt = count; |
5182 | |
|
5183 | 0 | if (mdrcnt > 0) { |
5184 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5185 | 0 | if (!*rdata) { |
5186 | 0 | return False; |
5187 | 0 | } |
5188 | 0 | } |
5189 | | |
5190 | 0 | desc.base = *rdata; |
5191 | 0 | desc.buflen = mdrcnt; |
5192 | 0 | if (init_package(&desc,queuecnt,0)) { |
5193 | 0 | succnt = 0; |
5194 | 0 | n = 0; |
5195 | 0 | for (i = 0; i < count; i++) { |
5196 | 0 | fill_printdest_info(&info[i].info2, uLevel,&desc); |
5197 | 0 | n++; |
5198 | 0 | if (desc.errcode == NERR_Success) { |
5199 | 0 | succnt = n; |
5200 | 0 | } |
5201 | 0 | } |
5202 | 0 | } |
5203 | 0 | out: |
5204 | 0 | *rdata_len = desc.usedlen; |
5205 | |
|
5206 | 0 | *rparam_len = 8; |
5207 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5208 | 0 | if (!*rparam) { |
5209 | 0 | return False; |
5210 | 0 | } |
5211 | 0 | SSVALS(*rparam,0,desc.errcode); |
5212 | 0 | SSVAL(*rparam,2,0); |
5213 | 0 | SSVAL(*rparam,4,succnt); |
5214 | 0 | SSVAL(*rparam,6,queuecnt); |
5215 | |
|
5216 | 0 | DEBUG(4,("WPrintDestEnumerate: errorcode %d\n",desc.errcode)); |
5217 | |
|
5218 | 0 | return True; |
5219 | 0 | } |
5220 | | |
5221 | | static bool api_WPrintDriverEnum(struct smbd_server_connection *sconn, |
5222 | | connection_struct *conn, uint64_t vuid, |
5223 | | char *param, int tpscnt, |
5224 | | char *data, int tdscnt, |
5225 | | int mdrcnt,int mprcnt, |
5226 | | char **rdata,char **rparam, |
5227 | | int *rdata_len,int *rparam_len) |
5228 | 0 | { |
5229 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
5230 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
5231 | 0 | char *p = skip_string(param,tpscnt,str2); |
5232 | 0 | int uLevel; |
5233 | 0 | int succnt; |
5234 | 0 | struct pack_desc desc; |
5235 | |
|
5236 | 0 | if (!str1 || !str2 || !p) { |
5237 | 0 | return False; |
5238 | 0 | } |
5239 | | |
5240 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5241 | |
|
5242 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5243 | |
|
5244 | 0 | DEBUG(3,("WPrintDriverEnum uLevel=%d\n",uLevel)); |
5245 | | |
5246 | | /* check it's a supported variant */ |
5247 | 0 | if (strcmp(str1,"WrLeh") != 0) { |
5248 | 0 | return False; |
5249 | 0 | } |
5250 | 0 | if (uLevel != 0 || strcmp(str2,"B41") != 0) { |
5251 | 0 | return False; |
5252 | 0 | } |
5253 | | |
5254 | 0 | if (mdrcnt > 0) { |
5255 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5256 | 0 | if (!*rdata) { |
5257 | 0 | return False; |
5258 | 0 | } |
5259 | 0 | } |
5260 | 0 | desc.base = *rdata; |
5261 | 0 | desc.buflen = mdrcnt; |
5262 | 0 | if (init_package(&desc,1,0)) { |
5263 | 0 | PACKS(&desc,"B41","NULL"); |
5264 | 0 | } |
5265 | |
|
5266 | 0 | succnt = (desc.errcode == NERR_Success ? 1 : 0); |
5267 | |
|
5268 | 0 | *rdata_len = desc.usedlen; |
5269 | |
|
5270 | 0 | *rparam_len = 8; |
5271 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5272 | 0 | if (!*rparam) { |
5273 | 0 | return False; |
5274 | 0 | } |
5275 | 0 | SSVALS(*rparam,0,desc.errcode); |
5276 | 0 | SSVAL(*rparam,2,0); |
5277 | 0 | SSVAL(*rparam,4,succnt); |
5278 | 0 | SSVAL(*rparam,6,1); |
5279 | |
|
5280 | 0 | DEBUG(4,("WPrintDriverEnum: errorcode %d\n",desc.errcode)); |
5281 | |
|
5282 | 0 | return True; |
5283 | 0 | } |
5284 | | |
5285 | | static bool api_WPrintQProcEnum(struct smbd_server_connection *sconn, |
5286 | | connection_struct *conn, uint64_t vuid, |
5287 | | char *param, int tpscnt, |
5288 | | char *data, int tdscnt, |
5289 | | int mdrcnt,int mprcnt, |
5290 | | char **rdata,char **rparam, |
5291 | | int *rdata_len,int *rparam_len) |
5292 | 0 | { |
5293 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
5294 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
5295 | 0 | char *p = skip_string(param,tpscnt,str2); |
5296 | 0 | int uLevel; |
5297 | 0 | int succnt; |
5298 | 0 | struct pack_desc desc; |
5299 | |
|
5300 | 0 | if (!str1 || !str2 || !p) { |
5301 | 0 | return False; |
5302 | 0 | } |
5303 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5304 | |
|
5305 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5306 | |
|
5307 | 0 | DEBUG(3,("WPrintQProcEnum uLevel=%d\n",uLevel)); |
5308 | | |
5309 | | /* check it's a supported variant */ |
5310 | 0 | if (strcmp(str1,"WrLeh") != 0) { |
5311 | 0 | return False; |
5312 | 0 | } |
5313 | 0 | if (uLevel != 0 || strcmp(str2,"B13") != 0) { |
5314 | 0 | return False; |
5315 | 0 | } |
5316 | | |
5317 | 0 | if (mdrcnt > 0) { |
5318 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5319 | 0 | if (!*rdata) { |
5320 | 0 | return False; |
5321 | 0 | } |
5322 | 0 | } |
5323 | 0 | desc.base = *rdata; |
5324 | 0 | desc.buflen = mdrcnt; |
5325 | 0 | desc.format = str2; |
5326 | 0 | if (init_package(&desc,1,0)) { |
5327 | 0 | PACKS(&desc,"B13","lpd"); |
5328 | 0 | } |
5329 | |
|
5330 | 0 | succnt = (desc.errcode == NERR_Success ? 1 : 0); |
5331 | |
|
5332 | 0 | *rdata_len = desc.usedlen; |
5333 | |
|
5334 | 0 | *rparam_len = 8; |
5335 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5336 | 0 | if (!*rparam) { |
5337 | 0 | return False; |
5338 | 0 | } |
5339 | 0 | SSVALS(*rparam,0,desc.errcode); |
5340 | 0 | SSVAL(*rparam,2,0); |
5341 | 0 | SSVAL(*rparam,4,succnt); |
5342 | 0 | SSVAL(*rparam,6,1); |
5343 | |
|
5344 | 0 | DEBUG(4,("WPrintQProcEnum: errorcode %d\n",desc.errcode)); |
5345 | |
|
5346 | 0 | return True; |
5347 | 0 | } |
5348 | | |
5349 | | static bool api_WPrintPortEnum(struct smbd_server_connection *sconn, |
5350 | | connection_struct *conn, uint64_t vuid, |
5351 | | char *param, int tpscnt, |
5352 | | char *data, int tdscnt, |
5353 | | int mdrcnt,int mprcnt, |
5354 | | char **rdata,char **rparam, |
5355 | | int *rdata_len,int *rparam_len) |
5356 | 0 | { |
5357 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
5358 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
5359 | 0 | char *p = skip_string(param,tpscnt,str2); |
5360 | 0 | int uLevel; |
5361 | 0 | int succnt; |
5362 | 0 | struct pack_desc desc; |
5363 | |
|
5364 | 0 | if (!str1 || !str2 || !p) { |
5365 | 0 | return False; |
5366 | 0 | } |
5367 | | |
5368 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5369 | |
|
5370 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5371 | |
|
5372 | 0 | DEBUG(3,("WPrintPortEnum uLevel=%d\n",uLevel)); |
5373 | | |
5374 | | /* check it's a supported variant */ |
5375 | 0 | if (strcmp(str1,"WrLeh") != 0) { |
5376 | 0 | return False; |
5377 | 0 | } |
5378 | 0 | if (uLevel != 0 || strcmp(str2,"B9") != 0) { |
5379 | 0 | return False; |
5380 | 0 | } |
5381 | | |
5382 | 0 | if (mdrcnt > 0) { |
5383 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5384 | 0 | if (!*rdata) { |
5385 | 0 | return False; |
5386 | 0 | } |
5387 | 0 | } |
5388 | 0 | memset((char *)&desc,'\0',sizeof(desc)); |
5389 | 0 | desc.base = *rdata; |
5390 | 0 | desc.buflen = mdrcnt; |
5391 | 0 | desc.format = str2; |
5392 | 0 | if (init_package(&desc,1,0)) { |
5393 | 0 | PACKS(&desc,"B13","lp0"); |
5394 | 0 | } |
5395 | |
|
5396 | 0 | succnt = (desc.errcode == NERR_Success ? 1 : 0); |
5397 | |
|
5398 | 0 | *rdata_len = desc.usedlen; |
5399 | |
|
5400 | 0 | *rparam_len = 8; |
5401 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5402 | 0 | if (!*rparam) { |
5403 | 0 | return False; |
5404 | 0 | } |
5405 | 0 | SSVALS(*rparam,0,desc.errcode); |
5406 | 0 | SSVAL(*rparam,2,0); |
5407 | 0 | SSVAL(*rparam,4,succnt); |
5408 | 0 | SSVAL(*rparam,6,1); |
5409 | |
|
5410 | 0 | DEBUG(4,("WPrintPortEnum: errorcode %d\n",desc.errcode)); |
5411 | |
|
5412 | 0 | return True; |
5413 | 0 | } |
5414 | | |
5415 | | /**************************************************************************** |
5416 | | List open sessions |
5417 | | ****************************************************************************/ |
5418 | | |
5419 | | static bool api_RNetSessionEnum(struct smbd_server_connection *sconn, |
5420 | | connection_struct *conn, uint64_t vuid, |
5421 | | char *param, int tpscnt, |
5422 | | char *data, int tdscnt, |
5423 | | int mdrcnt,int mprcnt, |
5424 | | char **rdata,char **rparam, |
5425 | | int *rdata_len,int *rparam_len) |
5426 | | |
5427 | 0 | { |
5428 | 0 | char *str1 = get_safe_str_ptr(param,tpscnt,param,2); |
5429 | 0 | char *str2 = skip_string(param,tpscnt,str1); |
5430 | 0 | char *p = skip_string(param,tpscnt,str2); |
5431 | 0 | int uLevel; |
5432 | 0 | struct pack_desc desc; |
5433 | 0 | int i; |
5434 | |
|
5435 | 0 | TALLOC_CTX *mem_ctx = talloc_tos(); |
5436 | 0 | WERROR werr; |
5437 | 0 | NTSTATUS status; |
5438 | 0 | struct rpc_pipe_client *cli = NULL; |
5439 | 0 | struct dcerpc_binding_handle *b = NULL; |
5440 | 0 | struct srvsvc_NetSessInfoCtr info_ctr; |
5441 | 0 | uint32_t totalentries, resume_handle = 0; |
5442 | 0 | uint32_t count = 0; |
5443 | |
|
5444 | 0 | if (!str1 || !str2 || !p) { |
5445 | 0 | return False; |
5446 | 0 | } |
5447 | | |
5448 | 0 | ZERO_STRUCT(desc); |
5449 | |
|
5450 | 0 | uLevel = get_safe_SVAL(param,tpscnt,p,0,-1); |
5451 | |
|
5452 | 0 | DEBUG(3,("RNetSessionEnum uLevel=%d\n",uLevel)); |
5453 | 0 | DEBUG(7,("RNetSessionEnum req string=%s\n",str1)); |
5454 | 0 | DEBUG(7,("RNetSessionEnum ret string=%s\n",str2)); |
5455 | | |
5456 | | /* check it's a supported variant */ |
5457 | 0 | if (strcmp(str1,RAP_NetSessionEnum_REQ) != 0) { |
5458 | 0 | return False; |
5459 | 0 | } |
5460 | 0 | if (uLevel != 2 || strcmp(str2,RAP_SESSION_INFO_L2) != 0) { |
5461 | 0 | return False; |
5462 | 0 | } |
5463 | | |
5464 | 0 | status = rpc_pipe_open_interface(mem_ctx, |
5465 | 0 | &ndr_table_srvsvc, |
5466 | 0 | conn->session_info, |
5467 | 0 | conn->sconn->remote_address, |
5468 | 0 | conn->sconn->local_address, |
5469 | 0 | conn->sconn->msg_ctx, |
5470 | 0 | &cli); |
5471 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5472 | 0 | DEBUG(0,("RNetSessionEnum: could not connect to srvsvc: %s\n", |
5473 | 0 | nt_errstr(status))); |
5474 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
5475 | 0 | goto out; |
5476 | 0 | } |
5477 | 0 | b = cli->binding_handle; |
5478 | |
|
5479 | 0 | info_ctr.level = 1; |
5480 | 0 | info_ctr.ctr.ctr1 = talloc_zero(talloc_tos(), struct srvsvc_NetSessCtr1); |
5481 | 0 | if (info_ctr.ctr.ctr1 == NULL) { |
5482 | 0 | desc.errcode = W_ERROR_V(WERR_NOT_ENOUGH_MEMORY); |
5483 | 0 | goto out; |
5484 | 0 | } |
5485 | | |
5486 | 0 | status = dcerpc_srvsvc_NetSessEnum(b, mem_ctx, |
5487 | 0 | cli->srv_name_slash, |
5488 | 0 | NULL, /* client */ |
5489 | 0 | NULL, /* user */ |
5490 | 0 | &info_ctr, |
5491 | 0 | (uint32_t)-1, /* max_buffer */ |
5492 | 0 | &totalentries, |
5493 | 0 | &resume_handle, |
5494 | 0 | &werr); |
5495 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5496 | 0 | DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n", |
5497 | 0 | nt_errstr(status))); |
5498 | 0 | desc.errcode = W_ERROR_V(ntstatus_to_werror(status)); |
5499 | 0 | goto out; |
5500 | 0 | } |
5501 | | |
5502 | 0 | if (!W_ERROR_IS_OK(werr)) { |
5503 | 0 | DEBUG(0,("RNetSessionEnum: dcerpc_srvsvc_NetSessEnum failed: %s\n", |
5504 | 0 | win_errstr(werr))); |
5505 | 0 | desc.errcode = W_ERROR_V(werr); |
5506 | 0 | goto out; |
5507 | 0 | } |
5508 | | |
5509 | 0 | count = info_ctr.ctr.ctr1->count; |
5510 | |
|
5511 | 0 | out: |
5512 | 0 | if (mdrcnt > 0) { |
5513 | 0 | *rdata = smb_realloc_limit(*rdata,mdrcnt); |
5514 | 0 | if (!*rdata) { |
5515 | 0 | return False; |
5516 | 0 | } |
5517 | 0 | } |
5518 | | |
5519 | 0 | desc.base = *rdata; |
5520 | 0 | desc.buflen = mdrcnt; |
5521 | 0 | desc.format = str2; |
5522 | 0 | if (!init_package(&desc, count,0)) { |
5523 | 0 | return False; |
5524 | 0 | } |
5525 | | |
5526 | 0 | for(i=0; i < count; i++) { |
5527 | 0 | PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].client); |
5528 | 0 | PACKS(&desc, "z", info_ctr.ctr.ctr1->array[i].user); |
5529 | 0 | PACKI(&desc, "W", 1); /* num conns */ |
5530 | 0 | PACKI(&desc, "W", info_ctr.ctr.ctr1->array[i].num_open); |
5531 | 0 | PACKI(&desc, "W", 1); /* num users */ |
5532 | 0 | PACKI(&desc, "D", 0); /* session time */ |
5533 | 0 | PACKI(&desc, "D", 0); /* idle time */ |
5534 | 0 | PACKI(&desc, "D", 0); /* flags */ |
5535 | 0 | PACKS(&desc, "z", "Unknown Client"); /* client type string */ |
5536 | 0 | } |
5537 | |
|
5538 | 0 | *rdata_len = desc.usedlen; |
5539 | |
|
5540 | 0 | *rparam_len = 8; |
5541 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5542 | 0 | if (!*rparam) { |
5543 | 0 | return False; |
5544 | 0 | } |
5545 | 0 | SSVALS(*rparam,0,desc.errcode); |
5546 | 0 | SSVAL(*rparam,2,0); /* converter */ |
5547 | 0 | SSVAL(*rparam,4, count); /* count */ |
5548 | |
|
5549 | 0 | DEBUG(4,("RNetSessionEnum: errorcode %d\n",desc.errcode)); |
5550 | |
|
5551 | 0 | return True; |
5552 | 0 | } |
5553 | | |
5554 | | |
5555 | | /**************************************************************************** |
5556 | | The buffer was too small. |
5557 | | ****************************************************************************/ |
5558 | | |
5559 | | static bool api_TooSmall(struct smbd_server_connection *sconn, |
5560 | | connection_struct *conn,uint64_t vuid, char *param, char *data, |
5561 | | int mdrcnt, int mprcnt, |
5562 | | char **rdata, char **rparam, |
5563 | | int *rdata_len, int *rparam_len) |
5564 | 0 | { |
5565 | 0 | *rparam_len = MIN(*rparam_len,mprcnt); |
5566 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5567 | 0 | if (!*rparam) { |
5568 | 0 | return False; |
5569 | 0 | } |
5570 | | |
5571 | 0 | *rdata_len = 0; |
5572 | |
|
5573 | 0 | SSVAL(*rparam,0,NERR_BufTooSmall); |
5574 | |
|
5575 | 0 | DEBUG(3,("Supplied buffer too small in API command\n")); |
5576 | |
|
5577 | 0 | return True; |
5578 | 0 | } |
5579 | | |
5580 | | /**************************************************************************** |
5581 | | The request is not supported. |
5582 | | ****************************************************************************/ |
5583 | | |
5584 | | static bool api_Unsupported(struct smbd_server_connection *sconn, |
5585 | | connection_struct *conn, uint64_t vuid, |
5586 | | char *param, int tpscnt, |
5587 | | char *data, int tdscnt, |
5588 | | int mdrcnt, int mprcnt, |
5589 | | char **rdata, char **rparam, |
5590 | | int *rdata_len, int *rparam_len) |
5591 | 0 | { |
5592 | 0 | *rparam_len = 4; |
5593 | 0 | *rparam = smb_realloc_limit(*rparam,*rparam_len); |
5594 | 0 | if (!*rparam) { |
5595 | 0 | return False; |
5596 | 0 | } |
5597 | | |
5598 | 0 | *rdata_len = 0; |
5599 | |
|
5600 | 0 | SSVAL(*rparam,0,NERR_notsupported); |
5601 | 0 | SSVAL(*rparam,2,0); /* converter word */ |
5602 | |
|
5603 | 0 | DEBUG(3,("Unsupported API command\n")); |
5604 | |
|
5605 | 0 | return True; |
5606 | 0 | } |
5607 | | |
5608 | | static const struct { |
5609 | | const char *name; |
5610 | | int id; |
5611 | | bool (*fn)(struct smbd_server_connection *sconn, |
5612 | | connection_struct *, uint64_t, |
5613 | | char *, int, |
5614 | | char *, int, |
5615 | | int,int,char **,char **,int *,int *); |
5616 | | bool auth_user; /* Deny anonymous access? */ |
5617 | | } api_commands[] = { |
5618 | | { |
5619 | | .name = "RNetShareEnum", |
5620 | | .id = RAP_WshareEnum, |
5621 | | .fn = api_RNetShareEnum, |
5622 | | .auth_user = true, |
5623 | | }, |
5624 | | { |
5625 | | .name = "RNetShareGetInfo", |
5626 | | .id = RAP_WshareGetInfo, |
5627 | | .fn = api_RNetShareGetInfo |
5628 | | }, |
5629 | | { |
5630 | | .name = "RNetShareAdd", |
5631 | | .id = RAP_WshareAdd, |
5632 | | .fn = api_RNetShareAdd |
5633 | | }, |
5634 | | { |
5635 | | .name = "RNetSessionEnum", |
5636 | | .id = RAP_WsessionEnum, |
5637 | | .fn = api_RNetSessionEnum, |
5638 | | .auth_user = true, |
5639 | | }, |
5640 | | { |
5641 | | .name = "RNetServerGetInfo", |
5642 | | .id = RAP_WserverGetInfo, |
5643 | | .fn = api_RNetServerGetInfo |
5644 | | }, |
5645 | | { |
5646 | | .name = "RNetGroupEnum", |
5647 | | .id = RAP_WGroupEnum, |
5648 | | .fn = api_RNetGroupEnum, True |
5649 | | }, |
5650 | | { |
5651 | | .name = "RNetGroupGetUsers", |
5652 | | .id = RAP_WGroupGetUsers, |
5653 | | .fn = api_RNetGroupGetUsers, |
5654 | | .auth_user = true}, |
5655 | | { |
5656 | | .name = "RNetUserEnum", |
5657 | | .id = RAP_WUserEnum, |
5658 | | .fn = api_RNetUserEnum, |
5659 | | .auth_user = true, |
5660 | | }, |
5661 | | { |
5662 | | .name = "RNetUserGetInfo", |
5663 | | .id = RAP_WUserGetInfo, |
5664 | | .fn = api_RNetUserGetInfo |
5665 | | }, |
5666 | | { |
5667 | | .name = "NetUserGetGroups", |
5668 | | .id = RAP_WUserGetGroups, |
5669 | | .fn = api_NetUserGetGroups |
5670 | | }, |
5671 | | { |
5672 | | .name = "NetWkstaGetInfo", |
5673 | | .id = RAP_WWkstaGetInfo, |
5674 | | .fn = api_NetWkstaGetInfo |
5675 | | }, |
5676 | | { |
5677 | | .name = "DosPrintQEnum", |
5678 | | .id = RAP_WPrintQEnum, |
5679 | | .fn = api_DosPrintQEnum, |
5680 | | .auth_user = true, |
5681 | | }, |
5682 | | { |
5683 | | .name = "DosPrintQGetInfo", |
5684 | | .id = RAP_WPrintQGetInfo, |
5685 | | .fn = api_DosPrintQGetInfo |
5686 | | }, |
5687 | | { |
5688 | | .name = "WPrintQueuePause", |
5689 | | .id = RAP_WPrintQPause, |
5690 | | .fn = api_WPrintQueueCtrl |
5691 | | }, |
5692 | | { |
5693 | | .name = "WPrintQueueResume", |
5694 | | .id = RAP_WPrintQContinue, |
5695 | | .fn = api_WPrintQueueCtrl |
5696 | | }, |
5697 | | { |
5698 | | .name = "WPrintJobEnumerate", |
5699 | | .id = RAP_WPrintJobEnum, |
5700 | | .fn = api_WPrintJobEnumerate |
5701 | | }, |
5702 | | { |
5703 | | .name = "WPrintJobGetInfo", |
5704 | | .id = RAP_WPrintJobGetInfo, |
5705 | | .fn = api_WPrintJobGetInfo |
5706 | | }, |
5707 | | { |
5708 | | .name = "RDosPrintJobDel", |
5709 | | .id = RAP_WPrintJobDel, |
5710 | | .fn = api_RDosPrintJobDel |
5711 | | }, |
5712 | | { |
5713 | | .name = "RDosPrintJobPause", |
5714 | | .id = RAP_WPrintJobPause, |
5715 | | .fn = api_RDosPrintJobDel |
5716 | | }, |
5717 | | { |
5718 | | .name = "RDosPrintJobResume", |
5719 | | .id = RAP_WPrintJobContinue, |
5720 | | .fn = api_RDosPrintJobDel |
5721 | | }, |
5722 | | { |
5723 | | .name = "WPrintDestEnum", |
5724 | | .id = RAP_WPrintDestEnum, |
5725 | | .fn = api_WPrintDestEnum |
5726 | | }, |
5727 | | { |
5728 | | .name = "WPrintDestGetInfo", |
5729 | | .id = RAP_WPrintDestGetInfo, |
5730 | | .fn = api_WPrintDestGetInfo |
5731 | | }, |
5732 | | { |
5733 | | .name = "NetRemoteTOD", |
5734 | | .id = RAP_NetRemoteTOD, |
5735 | | .fn = api_NetRemoteTOD |
5736 | | }, |
5737 | | { |
5738 | | .name = "WPrintQueuePurge", |
5739 | | .id = RAP_WPrintQPurge, |
5740 | | .fn = api_WPrintQueueCtrl |
5741 | | }, |
5742 | | { |
5743 | | .name = "NetServerEnum2", |
5744 | | .id = RAP_NetServerEnum2, |
5745 | | .fn = api_RNetServerEnum2 |
5746 | | }, /* anon OK */ |
5747 | | { |
5748 | | .name = "NetServerEnum3", |
5749 | | .id = RAP_NetServerEnum3, |
5750 | | .fn = api_RNetServerEnum3 |
5751 | | }, /* anon OK */ |
5752 | | { |
5753 | | .name = "WAccessGetUserPerms", |
5754 | | .id = RAP_WAccessGetUserPerms, |
5755 | | .fn = api_WAccessGetUserPerms |
5756 | | }, |
5757 | | { |
5758 | | .name = "WWkstaUserLogon", |
5759 | | .id = RAP_WWkstaUserLogon, |
5760 | | .fn = api_WWkstaUserLogon |
5761 | | }, |
5762 | | { |
5763 | | .name = "PrintJobInfo", |
5764 | | .id = RAP_WPrintJobSetInfo, |
5765 | | .fn = api_PrintJobInfo |
5766 | | }, |
5767 | | { |
5768 | | .name = "WPrintDriverEnum", |
5769 | | .id = RAP_WPrintDriverEnum, |
5770 | | .fn = api_WPrintDriverEnum |
5771 | | }, |
5772 | | { |
5773 | | .name = "WPrintQProcEnum", |
5774 | | .id = RAP_WPrintQProcessorEnum, |
5775 | | .fn = api_WPrintQProcEnum |
5776 | | }, |
5777 | | { |
5778 | | .name = "WPrintPortEnum", |
5779 | | .id = RAP_WPrintPortEnum, |
5780 | | .fn = api_WPrintPortEnum |
5781 | | }, |
5782 | | { |
5783 | | .name = "SamOEMChangePassword", |
5784 | | .id = RAP_SamOEMChgPasswordUser2_P, |
5785 | | .fn = api_SamOEMChangePassword |
5786 | | }, /* anon OK */ |
5787 | | { |
5788 | | .name = NULL, |
5789 | | .id = -1, |
5790 | | .fn = api_Unsupported} |
5791 | | /* |
5792 | | * The following RAP calls are not implemented by Samba: |
5793 | | * RAP_WFileEnum2 - anon not OK |
5794 | | */ |
5795 | | }; |
5796 | | |
5797 | | |
5798 | | /**************************************************************************** |
5799 | | Handle remote api calls. |
5800 | | ****************************************************************************/ |
5801 | | |
5802 | | void api_reply(connection_struct *conn, uint64_t vuid, |
5803 | | struct smb_request *req, |
5804 | | char *data, char *params, |
5805 | | int tdscnt, int tpscnt, |
5806 | | int mdrcnt, int mprcnt) |
5807 | 0 | { |
5808 | 0 | int api_command; |
5809 | 0 | char *rdata = NULL; |
5810 | 0 | char *rparam = NULL; |
5811 | 0 | const char *name1 = NULL; |
5812 | 0 | const char *name2 = NULL; |
5813 | 0 | int rdata_len = 0; |
5814 | 0 | int rparam_len = 0; |
5815 | 0 | bool reply=False; |
5816 | 0 | int i; |
5817 | |
|
5818 | 0 | if (!params) { |
5819 | 0 | DEBUG(0,("ERROR: NULL params in api_reply()\n")); |
5820 | 0 | reply_nterror(req, NT_STATUS_INVALID_PARAMETER); |
5821 | 0 | return; |
5822 | 0 | } |
5823 | | |
5824 | 0 | if (tpscnt < 2) { |
5825 | 0 | reply_nterror(req, NT_STATUS_INVALID_PARAMETER); |
5826 | 0 | return; |
5827 | 0 | } |
5828 | 0 | api_command = SVAL(params,0); |
5829 | | /* Is there a string at position params+2 ? */ |
5830 | 0 | if (skip_string(params,tpscnt,params+2)) { |
5831 | 0 | name1 = params + 2; |
5832 | 0 | } else { |
5833 | 0 | name1 = ""; |
5834 | 0 | } |
5835 | 0 | name2 = skip_string(params,tpscnt,params+2); |
5836 | 0 | if (!name2) { |
5837 | 0 | name2 = ""; |
5838 | 0 | } |
5839 | |
|
5840 | 0 | DEBUG(3,("Got API command %d of form <%s> <%s> (tdscnt=%d,tpscnt=%d,mdrcnt=%d,mprcnt=%d)\n", |
5841 | 0 | api_command, |
5842 | 0 | name1, |
5843 | 0 | name2, |
5844 | 0 | tdscnt,tpscnt,mdrcnt,mprcnt)); |
5845 | |
|
5846 | 0 | for (i=0;api_commands[i].name;i++) { |
5847 | 0 | if (api_commands[i].id == api_command && api_commands[i].fn) { |
5848 | 0 | DEBUG(3,("Doing %s\n",api_commands[i].name)); |
5849 | 0 | break; |
5850 | 0 | } |
5851 | 0 | } |
5852 | | |
5853 | | /* Check whether this api call can be done anonymously */ |
5854 | |
|
5855 | 0 | if (api_commands[i].auth_user && lp_restrict_anonymous()) { |
5856 | 0 | struct auth_session_info *si = NULL; |
5857 | 0 | NTSTATUS status; |
5858 | |
|
5859 | 0 | status = smbXsrv_session_info_lookup(conn->sconn->client, |
5860 | 0 | vuid, |
5861 | 0 | &si); |
5862 | 0 | if (!NT_STATUS_IS_OK(status)) { |
5863 | 0 | reply_nterror(req, NT_STATUS_ACCESS_DENIED); |
5864 | 0 | return; |
5865 | 0 | } |
5866 | | |
5867 | 0 | if (security_session_user_level(si, NULL) < SECURITY_USER) { |
5868 | 0 | reply_nterror(req, NT_STATUS_ACCESS_DENIED); |
5869 | 0 | return; |
5870 | 0 | } |
5871 | 0 | } |
5872 | | |
5873 | 0 | rdata = (char *)SMB_MALLOC(1024); |
5874 | 0 | if (rdata) { |
5875 | 0 | memset(rdata,'\0',1024); |
5876 | 0 | } |
5877 | |
|
5878 | 0 | rparam = (char *)SMB_MALLOC(1024); |
5879 | 0 | if (rparam) { |
5880 | 0 | memset(rparam,'\0',1024); |
5881 | 0 | } |
5882 | |
|
5883 | 0 | if(!rdata || !rparam) { |
5884 | 0 | DEBUG(0,("api_reply: malloc fail !\n")); |
5885 | 0 | SAFE_FREE(rdata); |
5886 | 0 | SAFE_FREE(rparam); |
5887 | 0 | reply_nterror(req, NT_STATUS_NO_MEMORY); |
5888 | 0 | return; |
5889 | 0 | } |
5890 | | |
5891 | 0 | reply = api_commands[i].fn(req->sconn, conn, |
5892 | 0 | vuid, |
5893 | 0 | params,tpscnt, /* params + length */ |
5894 | 0 | data,tdscnt, /* data + length */ |
5895 | 0 | mdrcnt,mprcnt, |
5896 | 0 | &rdata,&rparam,&rdata_len,&rparam_len); |
5897 | | |
5898 | |
|
5899 | 0 | if (rdata_len > mdrcnt || rparam_len > mprcnt) { |
5900 | 0 | reply = api_TooSmall(req->sconn,conn,vuid,params,data, |
5901 | 0 | mdrcnt,mprcnt, |
5902 | 0 | &rdata,&rparam,&rdata_len,&rparam_len); |
5903 | 0 | } |
5904 | | |
5905 | | /* if we get False back then it's actually unsupported */ |
5906 | 0 | if (!reply) { |
5907 | 0 | reply = api_Unsupported(req->sconn,conn,vuid,params,tpscnt, |
5908 | 0 | data, |
5909 | 0 | tdscnt,mdrcnt,mprcnt, |
5910 | 0 | &rdata,&rparam,&rdata_len,&rparam_len); |
5911 | 0 | } |
5912 | | |
5913 | | /* If api_Unsupported returns false we can't return anything. */ |
5914 | 0 | if (reply) { |
5915 | 0 | send_trans_reply(conn, req, rparam, rparam_len, |
5916 | 0 | rdata, rdata_len, False); |
5917 | 0 | } |
5918 | |
|
5919 | 0 | SAFE_FREE(rdata); |
5920 | | SAFE_FREE(rparam); |
5921 | 0 | return; |
5922 | 0 | } |