0
|
1 /*
|
|
2 * CDDL HEADER START
|
|
3 *
|
|
4 * The contents of this file are subject to the terms of the
|
|
5 * Common Development and Distribution License (the "License").
|
|
6 * You may not use this file except in compliance with the License.
|
|
7 *
|
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
9 * or http://www.opensolaris.org/os/licensing.
|
|
10 * See the License for the specific language governing permissions
|
|
11 * and limitations under the License.
|
|
12 *
|
|
13 * When distributing Covered Code, include this CDDL HEADER in each
|
|
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
15 * If applicable, add the following below this CDDL HEADER, with the
|
|
16 * fields enclosed by brackets "[]" replaced with your own identifying
|
|
17 * information: Portions Copyright [yyyy] [name of copyright owner]
|
|
18 *
|
|
19 * CDDL HEADER END
|
|
20 */
|
|
21
|
|
22 /*
|
|
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
|
24 * Use is subject to license terms.
|
|
25 */
|
|
26
|
|
27
|
|
28 #pragma ident "@(#)nsmb.c 1.1 08/02/13 SMI"
|
|
29
|
|
30 #include <sys/mdb_modapi.h>
|
|
31 #include <sys/types.h>
|
|
32
|
|
33 #include "smb_conn.h"
|
|
34 #include "smb_rq.h"
|
|
35 #include "smb_pass.h"
|
|
36
|
|
37 #define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */
|
|
38 #define OPT_RECURSE 0x0002 /* recursive display */
|
|
39
|
|
40 /*
|
|
41 * We need to read in a private copy
|
|
42 * of every string we want to print out.
|
|
43 */
|
|
44 void
|
|
45 print_str(uintptr_t addr)
|
|
46 {
|
|
47 char buf[32];
|
|
48 int len, mx = sizeof (buf) - 4;
|
|
49
|
|
50 if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) {
|
|
51 mdb_printf(" (%p)", addr);
|
|
52 } else {
|
|
53 if (len > mx)
|
|
54 strcpy(&buf[mx], "...");
|
|
55 mdb_printf(" %s", buf);
|
|
56 }
|
|
57 }
|
|
58
|
|
59
|
|
60 /*
|
|
61 * Walker for smb_connobj_t structures, including
|
|
62 * smb_vc_t and smb_share_t which "inherit" from it.
|
|
63 * Tricky: Exploit the "inheritance" of smb_connobj_t
|
|
64 * with common functions for walk_init, walk_next.
|
|
65 */
|
|
66 typedef struct smb_co_walk_data {
|
|
67 uintptr_t pp;
|
|
68 int level; /* SMBL_SM, SMBL_VC, SMBL_SHARE */
|
|
69 int size; /* sizeof (union member) */
|
|
70 union co_u {
|
|
71 smb_connobj_t co; /* copy of the list element */
|
|
72 smb_vc_t vc;
|
|
73 smb_share_t ss;
|
|
74 } u;
|
|
75 } smb_co_walk_data_t;
|
|
76
|
|
77 /*
|
|
78 * Common walk_init for walking structs inherited
|
|
79 * from smb_connobj_t (smb_vc_t, smb_share_t)
|
|
80 */
|
|
81 int
|
|
82 smb_co_walk_init(mdb_walk_state_t *wsp, int level)
|
|
83 {
|
|
84 smb_co_walk_data_t *smbw;
|
|
85 size_t psz;
|
|
86
|
|
87 if (wsp->walk_addr == NULL)
|
|
88 return (WALK_ERR);
|
|
89
|
|
90 smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC);
|
|
91 wsp->walk_data = smbw;
|
|
92
|
|
93 /*
|
|
94 * Save the parent pointer for later checks, and
|
|
95 * the level so we know which union member it is.
|
|
96 * Also the size of this union member.
|
|
97 */
|
|
98 smbw->pp = wsp->walk_addr;
|
|
99 smbw->level = level;
|
|
100 switch (level) {
|
|
101 case SMBL_SM:
|
|
102 smbw->size = sizeof (smbw->u.co);
|
|
103 break;
|
|
104 case SMBL_VC:
|
|
105 smbw->size = sizeof (smbw->u.vc);
|
|
106 break;
|
|
107 case SMBL_SHARE:
|
|
108 smbw->size = sizeof (smbw->u.ss);
|
|
109 break;
|
|
110 default:
|
|
111 smbw->size = sizeof (smbw->u);
|
|
112 break;
|
|
113 }
|
|
114
|
|
115 /*
|
|
116 * Read in the parent object. Just need the
|
|
117 * invariant part (smb_connobj_t) so we can
|
|
118 * get the list of children below it.
|
|
119 */
|
|
120 psz = sizeof (smbw->u.co);
|
|
121 if (mdb_vread(&smbw->u.co, psz, smbw->pp) != psz) {
|
|
122 mdb_warn("cannot read connobj from %p", smbw->pp);
|
|
123 return (WALK_ERR);
|
|
124 }
|
|
125
|
|
126 /*
|
|
127 * Finally, setup to walk the list of children.
|
|
128 */
|
|
129 wsp->walk_addr = (uintptr_t)smbw->u.co.co_children.slh_first;
|
|
130
|
|
131 return (WALK_NEXT);
|
|
132 }
|
|
133
|
|
134 /*
|
|
135 * Walk the (global) VC list.
|
|
136 */
|
|
137 int
|
|
138 smb_vc_walk_init(mdb_walk_state_t *wsp)
|
|
139 {
|
|
140 GElf_Sym sym;
|
|
141
|
|
142 if (wsp->walk_addr != NULL) {
|
|
143 mdb_warn("::walk smb_vc only supports global walks\n");
|
|
144 return (WALK_ERR);
|
|
145 }
|
|
146
|
|
147 /* Locate the VC list head. */
|
|
148 if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) {
|
|
149 mdb_warn("failed to lookup `smb_vclist'\n");
|
|
150 return (WALK_ERR);
|
|
151 }
|
|
152 wsp->walk_addr = sym.st_value;
|
|
153
|
|
154 return (smb_co_walk_init(wsp, SMBL_VC));
|
|
155 }
|
|
156
|
|
157 /*
|
|
158 * Walk the share list below some VC.
|
|
159 */
|
|
160 int
|
|
161 smb_ss_walk_init(mdb_walk_state_t *wsp)
|
|
162 {
|
|
163
|
|
164 /*
|
|
165 * Initial walk_addr is address of parent (VC)
|
|
166 */
|
|
167 if (wsp->walk_addr == 0) {
|
|
168 mdb_warn("::walk smb_ss does not support global walks\n");
|
|
169 return (WALK_ERR);
|
|
170 }
|
|
171
|
|
172 return (smb_co_walk_init(wsp, SMBL_SHARE));
|
|
173 }
|
|
174
|
|
175 /*
|
|
176 * Common walk_step for walking structs inherited
|
|
177 * from smb_connobj_t (smb_vc_t, smb_share_t)
|
|
178 */
|
|
179 int
|
|
180 smb_co_walk_step(mdb_walk_state_t *wsp)
|
|
181 {
|
|
182 smb_co_walk_data_t *smbw = wsp->walk_data;
|
|
183 int status;
|
|
184
|
|
185 if (wsp->walk_addr == NULL)
|
|
186 return (WALK_DONE);
|
|
187
|
|
188 if (mdb_vread(&smbw->u, smbw->size, wsp->walk_addr)
|
|
189 != smbw->size) {
|
|
190 mdb_warn("cannot read connobj from %p", wsp->walk_addr);
|
|
191 return (WALK_ERR);
|
|
192 }
|
|
193
|
|
194 /* XXX: Sanity check level? parent pointer? */
|
|
195
|
|
196 status = wsp->walk_callback(wsp->walk_addr, &smbw->u,
|
|
197 wsp->walk_cbdata);
|
|
198
|
|
199 wsp->walk_addr = (uintptr_t)smbw->u.co.co_next.sle_next;
|
|
200
|
|
201 return (status);
|
|
202 }
|
|
203
|
|
204
|
|
205 /*
|
|
206 * Dcmd (and callback function) to print a summary of
|
|
207 * all VCs, and optionally all shares under each VC.
|
|
208 */
|
|
209
|
|
210 typedef struct smb_co_cbdata {
|
|
211 int flags; /* OPT_... */
|
|
212 int printed_header;
|
|
213 } smb_co_cbdata_t;
|
|
214
|
|
215 /*
|
|
216 * Call-back function for walking a share list.
|
|
217 */
|
|
218 int
|
|
219 smb_ss_cb(uintptr_t addr, const void *data, void *arg)
|
|
220 {
|
|
221 const smb_share_t *ssp = data;
|
|
222 smb_co_cbdata_t *cbd = arg;
|
|
223
|
|
224 mdb_printf(" %-p", addr);
|
|
225 print_str((uintptr_t)ssp->ss_name);
|
|
226 mdb_printf("\n");
|
|
227
|
|
228 if (cbd->flags & OPT_VERBOSE) {
|
|
229 mdb_inc_indent(2);
|
|
230 /* Anything wanted here? */
|
|
231 mdb_dec_indent(2);
|
|
232 }
|
|
233
|
|
234 return (WALK_NEXT);
|
|
235 }
|
|
236
|
|
237 /*
|
|
238 * Call-back function for walking the VC list.
|
|
239 */
|
|
240 int
|
|
241 smb_vc_cb(uintptr_t addr, const void *data, void *arg)
|
|
242 {
|
|
243 const smb_vc_t *vcp = data;
|
|
244 smb_co_cbdata_t *cbd = arg;
|
|
245
|
|
246 if (cbd->printed_header == 0) {
|
|
247 cbd->printed_header = 1;
|
|
248 mdb_printf("// smb_vc_t uid server user\n");
|
|
249 }
|
|
250
|
|
251 mdb_printf("%-p", addr);
|
|
252 mdb_printf(" %d", vcp->vc_uid);
|
|
253 print_str((uintptr_t)vcp->vc_srvname);
|
|
254 print_str((uintptr_t)vcp->vc_username);
|
|
255 mdb_printf("\n");
|
|
256
|
|
257 if (cbd->flags & OPT_RECURSE) {
|
|
258 mdb_inc_indent(2);
|
|
259 if (mdb_pwalk("nsmb_ss", smb_ss_cb, cbd, addr) < 0) {
|
|
260 mdb_warn("failed to walk 'nsmb_ss'");
|
|
261 /* Don't: return (WALK_ERR); */
|
|
262 }
|
|
263 mdb_dec_indent(2);
|
|
264 }
|
|
265
|
|
266 return (WALK_NEXT);
|
|
267 }
|
|
268
|
|
269 int
|
|
270 smb_vc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
|
|
271 {
|
|
272 smb_co_cbdata_t cbd;
|
|
273 smb_vc_t *vcp;
|
|
274 size_t vcsz;
|
|
275
|
|
276 memset(&cbd, 0, sizeof (cbd));
|
|
277
|
|
278 if (mdb_getopts(argc, argv,
|
|
279 'r', MDB_OPT_SETBITS, OPT_RECURSE, &cbd.flags,
|
|
280 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd.flags,
|
|
281 NULL) != argc) {
|
|
282 return (DCMD_USAGE);
|
|
283 }
|
|
284
|
|
285 if (!(flags & DCMD_ADDRSPEC)) {
|
|
286 if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) {
|
|
287 mdb_warn("failed to walk 'nsmb_vc'");
|
|
288 return (DCMD_ERR);
|
|
289 }
|
|
290 return (DCMD_OK);
|
|
291 }
|
|
292
|
|
293 vcsz = sizeof (*vcp);
|
|
294 vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC);
|
|
295 if (mdb_vread(vcp, vcsz, addr) != vcsz) {
|
|
296 mdb_warn("cannot read VC from %p", addr);
|
|
297 return (DCMD_ERR);
|
|
298 }
|
|
299 smb_vc_cb(addr, vcp, &cbd);
|
|
300
|
|
301 return (DCMD_OK);
|
|
302 }
|
|
303
|
|
304 void
|
|
305 smb_vc_help(void)
|
|
306 {
|
|
307 mdb_printf("Options:\n"
|
|
308 " -r recursive display of share lists\n"
|
|
309 " -v be verbose when displaying smb_vc\n");
|
|
310 }
|
|
311
|
|
312 /*
|
|
313 * Walker for the request list on a VC,
|
|
314 * and dcmd to show a summary.
|
|
315 */
|
|
316 int
|
|
317 rqlist_walk_init(mdb_walk_state_t *wsp)
|
|
318 {
|
|
319 struct smb_rqhead rqh;
|
|
320 uintptr_t addr;
|
|
321
|
|
322 /*
|
|
323 * Initial walk_addr is the address of the VC.
|
|
324 * Add offsetof(iod_rqlist) to get the rqhead.
|
|
325 */
|
|
326 if (wsp->walk_addr == 0) {
|
|
327 mdb_warn("::walk smb_ss does not support global walks\n");
|
|
328 return (WALK_ERR);
|
|
329 }
|
|
330 addr = wsp->walk_addr;
|
|
331 addr += OFFSETOF(smb_vc_t, iod_rqlist);
|
|
332
|
|
333 if (mdb_vread(&rqh, sizeof (rqh), addr) == -1) {
|
|
334 mdb_warn("failed to read smb_rqhead at %p", addr);
|
|
335 return (WALK_ERR);
|
|
336 }
|
|
337 wsp->walk_addr = (uintptr_t)rqh.tqh_first;
|
|
338
|
|
339 return (WALK_NEXT);
|
|
340 }
|
|
341
|
|
342 int
|
|
343 rqlist_walk_step(mdb_walk_state_t *wsp)
|
|
344 {
|
|
345 smb_rq_t rq;
|
|
346 int status;
|
|
347
|
|
348 if (wsp->walk_addr == NULL)
|
|
349 return (WALK_DONE);
|
|
350
|
|
351 if (mdb_vread(&rq, sizeof (rq), wsp->walk_addr) == -1) {
|
|
352 mdb_warn("cannot read smb_rq from %p", wsp->walk_addr);
|
|
353 return (WALK_ERR);
|
|
354 }
|
|
355
|
|
356 status = wsp->walk_callback(wsp->walk_addr, &rq,
|
|
357 wsp->walk_cbdata);
|
|
358
|
|
359 wsp->walk_addr = (uintptr_t)rq.sr_link.tqe_next;
|
|
360
|
|
361 return (status);
|
|
362 }
|
|
363
|
|
364 typedef struct rqlist_cbdata {
|
|
365 int printed_header;
|
|
366 uintptr_t uid; /* optional filtering by UID */
|
|
367 } rqlist_cbdata_t;
|
|
368
|
|
369 int
|
|
370 rqlist_cb(uintptr_t addr, const void *data, void *arg)
|
|
371 {
|
|
372 const smb_rq_t *rq = data;
|
|
373 rqlist_cbdata_t *cbd = arg;
|
|
374
|
|
375 if (cbd->printed_header == 0) {
|
|
376 cbd->printed_header = 1;
|
|
377 mdb_printf("// smb_rq_t MID cmd sr_state sr_flags\n");
|
|
378 }
|
|
379
|
|
380 mdb_printf(" %-p", addr); /* smb_rq_t */
|
|
381 mdb_printf(" x%04x", rq->sr_mid);
|
|
382 mdb_printf(" x%02x", rq->sr_cmd);
|
|
383 mdb_printf(" %d", rq->sr_state);
|
|
384 mdb_printf(" x%x", rq->sr_flags);
|
|
385 mdb_printf("\n");
|
|
386
|
|
387 return (WALK_NEXT);
|
|
388 }
|
|
389
|
|
390 /*ARGSUSED*/
|
|
391 int
|
|
392 rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
|
|
393 {
|
|
394 rqlist_cbdata_t cbd;
|
|
395
|
|
396 memset(&cbd, 0, sizeof (cbd));
|
|
397
|
|
398 /*
|
|
399 * Initial walk_addr is address of parent (VC)
|
|
400 */
|
|
401 if (!(flags & DCMD_ADDRSPEC)) {
|
|
402 mdb_warn("address required\n");
|
|
403 return (DCMD_ERR);
|
|
404 }
|
|
405
|
|
406 if (mdb_pwalk("nsmb_rqlist", rqlist_cb, &cbd, addr) == -1) {
|
|
407 mdb_warn("failed to walk 'nsmb_rqlist'");
|
|
408 return (DCMD_ERR);
|
|
409 }
|
|
410
|
|
411 return (DCMD_OK);
|
|
412 }
|
|
413
|
|
414
|
|
415 /*
|
|
416 * AVL walker for the passwords AVL tree,
|
|
417 * and dcmd to show a summary.
|
|
418 */
|
|
419 static int
|
|
420 pwtree_walk_init(mdb_walk_state_t *wsp)
|
|
421 {
|
|
422 GElf_Sym sym;
|
|
423
|
|
424 if (wsp->walk_addr != NULL) {
|
|
425 mdb_warn("pwtree walk only supports global walks\n");
|
|
426 return (WALK_ERR);
|
|
427 }
|
|
428
|
|
429 if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) {
|
|
430 mdb_warn("failed to find symbol 'smb_ptd'");
|
|
431 return (WALK_ERR);
|
|
432 }
|
|
433
|
|
434 wsp->walk_addr = (uintptr_t)sym.st_value;
|
|
435
|
|
436 if (mdb_layered_walk("avl", wsp) == -1) {
|
|
437 mdb_warn("failed to walk 'avl'\n");
|
|
438 return (WALK_ERR);
|
|
439 }
|
|
440
|
|
441 return (WALK_NEXT);
|
|
442 }
|
|
443
|
|
444 static int
|
|
445 pwtree_walk_step(mdb_walk_state_t *wsp)
|
|
446 {
|
|
447 smb_passid_t ptnode;
|
|
448
|
|
449 if (mdb_vread(&ptnode, sizeof (ptnode), wsp->walk_addr) == -1) {
|
|
450 mdb_warn("failed to read smb_passid_t at %p", wsp->walk_addr);
|
|
451 return (WALK_ERR);
|
|
452 }
|
|
453
|
|
454 return (wsp->walk_callback(wsp->walk_addr, &ptnode, wsp->walk_cbdata));
|
|
455 }
|
|
456
|
|
457 typedef struct pwtree_cbdata {
|
|
458 int printed_header;
|
|
459 uid_t uid; /* optional filtering by UID */
|
|
460 } pwtree_cbdata_t;
|
|
461
|
|
462 int
|
|
463 pwtree_cb(uintptr_t addr, const void *data, void *arg)
|
|
464 {
|
|
465 const smb_passid_t *ptn = data;
|
|
466 pwtree_cbdata_t *cbd = arg;
|
|
467
|
|
468 /* Optional filtering by UID. */
|
|
469 if (cbd->uid != (uid_t)-1 && cbd->uid != ptn->uid) {
|
|
470 return (WALK_NEXT);
|
|
471 }
|
|
472
|
|
473 if (cbd->printed_header == 0) {
|
|
474 cbd->printed_header = 1;
|
|
475 mdb_printf("// smb_passid_t UID domain user\n");
|
|
476 }
|
|
477
|
|
478 mdb_printf(" %-p", addr); /* smb_passid_t */
|
|
479 mdb_printf(" %d", (uintptr_t)ptn->uid);
|
|
480 print_str((uintptr_t)ptn->srvdom);
|
|
481 print_str((uintptr_t)ptn->username);
|
|
482 mdb_printf("\n");
|
|
483
|
|
484 return (WALK_NEXT);
|
|
485 }
|
|
486
|
|
487 /*ARGSUSED*/
|
|
488 int
|
|
489 pwtree_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
|
|
490 {
|
|
491 pwtree_cbdata_t cbd;
|
|
492 char *uid_str = NULL;
|
|
493 char buf[32];
|
|
494
|
|
495 memset(&cbd, 0, sizeof (cbd));
|
|
496
|
|
497 if (mdb_getopts(argc, argv,
|
|
498 'u', MDB_OPT_STR, &uid_str, NULL) != argc) {
|
|
499 return (DCMD_USAGE);
|
|
500 }
|
|
501 if (uid_str) {
|
|
502 /*
|
|
503 * Want the the default radix to be 10 here.
|
|
504 * If the string has some kind of radix prefix,
|
|
505 * just use that as-is, otherwise prepend "0t".
|
|
506 * Cheating on the "not a digit" test, but
|
|
507 * mdb_strtoull will do a real syntax check.
|
|
508 */
|
|
509 if (uid_str[0] == '0' && uid_str[1] > '9') {
|
|
510 cbd.uid = (uid_t)mdb_strtoull(uid_str);
|
|
511 } else {
|
|
512 strcpy(buf, "0t");
|
|
513 strlcat(buf, uid_str, sizeof (buf));
|
|
514 cbd.uid = (uid_t)mdb_strtoull(buf);
|
|
515 }
|
|
516 } else
|
|
517 cbd.uid = (uid_t)-1;
|
|
518
|
|
519 if (flags & DCMD_ADDRSPEC) {
|
|
520 mdb_warn("address not allowed\n");
|
|
521 return (DCMD_ERR);
|
|
522 }
|
|
523
|
|
524 if (mdb_pwalk("nsmb_pwtree", pwtree_cb, &cbd, 0) == -1) {
|
|
525 mdb_warn("failed to walk 'nsmb_pwtree'");
|
|
526 return (DCMD_ERR);
|
|
527 }
|
|
528
|
|
529 return (DCMD_OK);
|
|
530 }
|
|
531
|
|
532 void
|
|
533 pwtree_help(void)
|
|
534 {
|
|
535 mdb_printf("Options:\n"
|
|
536 " -u uid show only entries belonging to uid (decimal)\n");
|
|
537 }
|
|
538
|
|
539
|
|
540 static const mdb_dcmd_t dcmds[] = {
|
|
541 { "nsmb_vc", "?[-rv]",
|
|
542 "show smb_vc (or list)",
|
|
543 smb_vc_dcmd, smb_vc_help },
|
|
544 { "nsmb_rqlist", ":",
|
|
545 "show smb_rq list on a VC",
|
|
546 rqlist_dcmd, NULL },
|
|
547 { "nsmb_pwtree", "?[-u uid]",
|
|
548 "list smb_passid_t (password tree)",
|
|
549 pwtree_dcmd, pwtree_help },
|
|
550 {NULL}
|
|
551 };
|
|
552
|
|
553 static const mdb_walker_t walkers[] = {
|
|
554 { "nsmb_vc", "walk nsmb VC list",
|
|
555 smb_vc_walk_init, smb_co_walk_step, NULL },
|
|
556 { "nsmb_ss", "walk nsmb share list for some VC",
|
|
557 smb_ss_walk_init, smb_co_walk_step, NULL },
|
|
558 { "nsmb_rqlist", "walk request list for some VC",
|
|
559 rqlist_walk_init, rqlist_walk_step, NULL },
|
|
560 { "nsmb_pwtree", "walk passord AVL tree",
|
|
561 pwtree_walk_init, pwtree_walk_step, NULL },
|
|
562 {NULL}
|
|
563 };
|
|
564
|
|
565 static const mdb_modinfo_t modinfo = {
|
|
566 MDB_API_VERSION,
|
|
567 dcmds,
|
|
568 walkers
|
|
569 };
|
|
570
|
|
571 const mdb_modinfo_t *
|
|
572 _mdb_init(void)
|
|
573 {
|
|
574 return (&modinfo);
|
|
575 }
|