added some options and enhancements to the print output:
[obnox/wireshark/wip.git] / packet-smb-sidsnooping.c
1 /* packet-smb-sidsnooping.c
2  * Routines for snooping SID to name mappings
3  * Copyright 2003, Ronnie Sahlberg
4  *
5  * $Id: packet-smb-sidsnooping.c,v 1.10 2003/12/02 21:15:46 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32 #include "epan/packet_info.h"
33 #include "epan/epan_dissect.h"
34 #include "epan/proto.h"
35 #include "tap.h"
36 #include "packet-dcerpc.h"
37 #include "packet-dcerpc-nt.h"
38 #include "register.h"
39 #include "smb.h"
40 #include "packet-smb-sidsnooping.h"
41
42 static int hf_lsa = -1;
43 static int hf_lsa_info_level = -1;
44 static int hf_lsa_opnum = -1;
45 static int hf_lsa_domain = -1;
46 static int hf_lsa_domain_sid = -1;
47 static int hf_samr_hnd = -1;
48 static int hf_samr_rid = -1;
49 static int hf_samr_acct_name = -1;
50 static int hf_samr_level = -1;
51
52
53
54 GHashTable *sid_name_table = NULL;
55 static GMemChunk *sid_name_chunk = NULL;
56 static int sid_name_init_count = 200;
57
58
59
60 static GMemChunk *ctx_handle_chunk = NULL;
61 static int ctx_handle_init_count = 200;
62 static GHashTable *ctx_handle_table = NULL;
63
64
65 static void *lsa_policy_information_flag = NULL;
66 static void *samr_query_dispinfo_flag = NULL;
67
68
69 char *
70 find_sid_name(char *sid)
71 {
72         sid_name *sn;
73         sid_name old_sn;
74
75         old_sn.sid=sid;
76         sn=g_hash_table_lookup(sid_name_table, &old_sn);
77         if(!sn){
78                 return NULL;
79         }
80         return sn->name;
81 }
82
83 static void
84 add_sid_name_mapping(char *sid, char *name)
85 {
86         sid_name *sn;
87         sid_name old_sn;
88
89         old_sn.sid=sid;
90         sn=g_hash_table_lookup(sid_name_table, &old_sn);
91         if(sn){
92                 return;
93         }
94
95         sn=g_mem_chunk_alloc(sid_name_chunk);
96         sn->sid=g_strdup(sid);
97         sn->name=g_strdup(name);
98         g_hash_table_insert(sid_name_table, sn, sn);
99 }
100
101
102
103 /*
104  * QueryDispInfo :
105  * level  1 : user displayinfo 1
106  */
107 static int
108 samr_query_dispinfo(void *dummy _U_, packet_info *pinfo, epan_dissect_t *edt, void *pri)
109 {
110         dcerpc_info *ri=pri;
111         void *old_ctx=NULL;
112         char *pol_name;
113         char *sid;
114         int sid_len;
115         int num_rids;
116         int num_names;
117         GPtrArray *gp;
118         GPtrArray *gp_rids;
119         GPtrArray *gp_names;
120         field_info *fi;
121         field_info *fi_rid;
122         field_info *fi_name;
123         char sid_name[256];
124         int info_level;
125
126         gp=proto_get_finfo_ptr_array(edt->tree, hf_samr_level);
127         if(!gp || gp->len!=1){
128                 return 0;
129         }
130         fi=gp->pdata[0];
131         info_level=fi->value.value.integer;
132
133         if(info_level!=1){
134                 return 0;
135         }
136
137         if(!ri){
138                 return 0;
139         }
140         if(!ri->call_data){
141                 return 0;
142         }
143         if(ri->request){
144                 gp=proto_get_finfo_ptr_array(edt->tree, hf_samr_hnd);
145                 if(!gp || gp->len!=1){
146                         return 0;
147                 }
148                 fi=gp->pdata[0];
149
150                 old_ctx=g_hash_table_lookup(ctx_handle_table, (gpointer)pinfo->fd->num);
151                 if(old_ctx){
152                         g_hash_table_remove(ctx_handle_table, (gpointer)pinfo->fd->num);
153                 }
154                 if(!old_ctx){
155                         old_ctx=g_mem_chunk_alloc(ctx_handle_chunk);
156                         memcpy(old_ctx, fi->value.value.bytes->data, 20);
157                 }
158                 g_hash_table_insert(ctx_handle_table, (gpointer)pinfo->fd->num, old_ctx);
159
160                 return 0;
161         }
162
163         if(!ri->call_data->req_frame){
164                 return 0;
165         }
166
167         old_ctx=g_hash_table_lookup(ctx_handle_table, (gpointer)ri->call_data->req_frame);
168         if(!old_ctx){
169                 return 0;
170         }
171
172         if (!dcerpc_smb_fetch_pol(old_ctx, &pol_name, NULL, NULL, ri->call_data->req_frame)) {
173                 return 0;
174         }
175
176         sid=strstr(pol_name,"S-1-5");
177         if(!sid){
178                 return 0;
179         }
180
181         for(sid_len=4;1;sid_len++){
182                 if((sid[sid_len]>='0') && (sid[sid_len]<='9')){
183                         continue;
184                 }
185                 if(sid[sid_len]=='-'){
186                         continue;
187                 }
188                 break;
189         }
190
191         gp_rids=proto_get_finfo_ptr_array(edt->tree, hf_samr_rid);
192         if(!gp_rids || gp_rids->len<1){
193                 return 0;
194         }
195         num_rids=gp_rids->len;
196         gp_names=proto_get_finfo_ptr_array(edt->tree, hf_samr_acct_name);
197         if(!gp_names || gp_names->len<1){
198                 return 0;
199         }
200         num_names=gp_names->len;
201
202         if(num_rids>num_names){
203                 num_rids=num_names;
204         }
205
206         for(;num_rids;num_rids--){
207                 int len=sid_len;
208
209                 fi_rid=gp_rids->pdata[num_rids-1];
210                 fi_name=gp_names->pdata[num_rids-1];
211                 strncpy(sid_name, sid, len);
212                 sid_name[len++]='-';
213                 len+=sprintf(sid_name+len,"%d",fi_rid->value.value.integer);
214                 sid_name[len]=0;
215                 add_sid_name_mapping(sid_name, fi_name->value.value.string);
216         }
217         return 1;
218 }
219
220 /*
221  * PolicyInformation :
222  * level  3 : PRIMARY_DOMAIN_INFO lsa.domain_sid -> lsa.domain
223  * level  5 : ACCOUNT_DOMAIN_INFO lsa.domain_sid -> lsa.domain
224  * level 12 : DNS_DOMAIN_INFO     lsa.domain_sid -> lsa.domain
225  */
226 static int
227 lsa_policy_information(void *dummy _U_, packet_info *pinfo _U_, epan_dissect_t *edt, void *pri _U_)
228 {
229         GPtrArray *gp;
230         field_info *fi;
231         char *domain;
232         char *sid;
233         int info_level;
234
235         gp=proto_get_finfo_ptr_array(edt->tree, hf_lsa_info_level);
236         if(!gp || gp->len!=1){
237                 return 0;
238         }
239         fi=gp->pdata[0];
240         info_level=fi->value.value.integer;
241
242         switch(info_level){
243         case 3:
244         case 5:
245         case 12:
246                 gp=proto_get_finfo_ptr_array(edt->tree, hf_lsa_domain);
247                 if(!gp || gp->len!=1){
248                         return 0;
249                 }
250                 fi=gp->pdata[0];
251                 domain=fi->value.value.string;
252
253                 gp=proto_get_finfo_ptr_array(edt->tree, hf_lsa_domain_sid);
254                 if(!gp || gp->len!=1){
255                         return 0;
256                 }
257                 fi=gp->pdata[0];
258                 sid=fi->value.value.string;
259
260                 add_sid_name_mapping(sid, domain);
261                 break;
262         }
263         return 0;
264 }
265
266 static gboolean
267 free_all_sid_names(gpointer key_arg, gpointer value _U_, gpointer user_data _U_)
268 {
269         sid_name *sn = (sid_name *)key_arg;
270
271         if(sn->sid){
272                 g_free((gpointer)sn->sid);
273                 sn->sid=NULL;
274         }
275         if(sn->name){
276                 g_free((gpointer)sn->name);
277                 sn->name=NULL;
278         }
279         return TRUE;
280 }
281
282 static gint
283 sid_name_equal(gconstpointer k1, gconstpointer k2)
284 {
285         const sid_name *sn1 = (const sid_name *)k1;
286         const sid_name *sn2 = (const sid_name *)k2;
287         
288         return !strcmp(sn1->sid, sn2->sid);
289 }
290
291 static guint
292 sid_name_hash(gconstpointer k)
293 {
294         const sid_name *sn = (const sid_name *)k;
295         int i, sum;
296
297         for(sum=0,i=strlen(sn->sid)-1;i>=0;i--){
298                 sum+=sn->sid[i];
299         }
300
301         return sum;
302 }
303
304
305 static gboolean
306 free_all_ctx_handle(gpointer key_arg _U_, gpointer value _U_, gpointer user_data _U_)
307 {
308         return TRUE;
309 }
310 static gint
311 ctx_handle_equal(gconstpointer k1, gconstpointer k2)
312 {
313         int sn1 = (int)k1;
314         int sn2 = (int)k2;
315         
316         return sn1==sn2;
317 }
318
319 static guint
320 ctx_handle_hash(gconstpointer k)
321 {
322         int sn = (int)k;
323
324         return sn;
325 }
326
327
328 static void
329 sid_snooping_init(void)
330 {
331         header_field_info *hfi;
332         GString *error_string;
333
334         if(lsa_policy_information_flag){
335                 remove_tap_listener(lsa_policy_information_flag);
336                 lsa_policy_information_flag=NULL;
337         }
338         if(samr_query_dispinfo_flag){
339                 remove_tap_listener(samr_query_dispinfo_flag);
340                 samr_query_dispinfo_flag=NULL;
341         }
342
343         if(sid_name_table){
344                 g_hash_table_foreach_remove(sid_name_table, free_all_sid_names, NULL);
345                 sid_name_table=NULL;
346         }
347         if(sid_name_chunk){
348                 g_mem_chunk_destroy(sid_name_chunk);
349                 sid_name_chunk=NULL;
350         }
351         if(ctx_handle_table){
352                 g_hash_table_foreach_remove(ctx_handle_table, free_all_ctx_handle, NULL);
353                 ctx_handle_table=NULL;
354         }
355         if(ctx_handle_chunk){
356                 g_mem_chunk_destroy(ctx_handle_chunk);
357                 ctx_handle_chunk=NULL;
358         }
359
360
361         if(!sid_name_snooping){
362                 return;
363         }
364
365
366         sid_name_table=g_hash_table_new(sid_name_hash, sid_name_equal);
367         sid_name_chunk = g_mem_chunk_new("sid_name_chunk",
368             sizeof(sid_name),
369             sid_name_init_count * sizeof(sid_name),
370             G_ALLOC_ONLY);
371
372
373         ctx_handle_table=g_hash_table_new(ctx_handle_hash, ctx_handle_equal);
374         ctx_handle_chunk = g_mem_chunk_new("ctx_handle_chunk",
375             20,  /* our dcerpc context handles are 20 bytes */
376             ctx_handle_init_count * 20,
377             G_ALLOC_ONLY);
378
379
380         hf_lsa=proto_get_id_by_filter_name("lsa");
381
382         hfi=proto_registrar_get_byname("lsa.opnum");
383         if(hfi){
384                 hf_lsa_opnum=hfi->id;
385         }
386
387         hfi=proto_registrar_get_byname("lsa.domain_sid");
388         if(hfi){
389                 hf_lsa_domain_sid=hfi->id;
390         }
391
392         hfi=proto_registrar_get_byname("lsa.domain");
393         if(hfi){
394                 hf_lsa_domain=hfi->id;
395         }
396
397         hfi=proto_registrar_get_byname("lsa.info.level");
398         if(hfi){
399                 hf_lsa_info_level=hfi->id;
400         }
401
402         hfi=proto_registrar_get_byname("samr.hnd");
403         if(hfi){
404                 hf_samr_hnd=hfi->id;
405         }
406         hfi=proto_registrar_get_byname("samr.rid");
407         if(hfi){
408                 hf_samr_rid=hfi->id;
409         }
410         hfi=proto_registrar_get_byname("samr.acct_name");
411         if(hfi){
412                 hf_samr_acct_name=hfi->id;
413         }
414         hfi=proto_registrar_get_byname("samr.level");
415         if(hfi){
416                 hf_samr_level=hfi->id;
417         }
418
419
420
421         error_string=register_tap_listener("dcerpc", lsa_policy_information, "lsa.policy_information and ( lsa.info.level or lsa.domain or lsa.domain_sid )", NULL, lsa_policy_information, NULL);
422         if(error_string){
423                 /* error, we failed to attach to the tap. clean up */
424
425                 fprintf(stderr, "tethereal: Couldn't register proto_reg_handoff_smb_sidsnooping()/lsa_policy_information tap: %s\n",
426                     error_string->str);
427                 g_string_free(error_string, TRUE);
428                 exit(1);
429         }
430         lsa_policy_information_flag=lsa_policy_information;
431
432         error_string=register_tap_listener("dcerpc", samr_query_dispinfo, "samr and samr.opnum==40 and ( samr.hnd or samr.rid or samr.acct_name or samr.level )", NULL, samr_query_dispinfo, NULL);
433         if(error_string){
434                 /* error, we failed to attach to the tap. clean up */
435
436                 fprintf(stderr, "tethereal: Couldn't register proto_reg_handoff_smb_sidsnooping()/samr_query_dispinfo tap: %s\n",
437                     error_string->str);
438                 g_string_free(error_string, TRUE);
439                 exit(1);
440         }
441         samr_query_dispinfo_flag=samr_query_dispinfo;
442 }
443
444 void
445 proto_register_smb_sidsnooping(void)
446 {
447         register_init_routine(sid_snooping_init);
448 }
449
450 void
451 proto_reg_handoff_smb_sidsnooping(void)
452 {
453 }
454