added frag field to make_rpc_hdr() function
[Samba.git] / source / smbparse.c
blobed6ab248cb4918f135fa386eee5939a8325c1032
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Samba utility functions
5 Copyright (C) Luke Leighton 1996 - 1997 Paul Ashton 1997
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
26 /*******************************************************************
27 reads or writes a UTIME type.
28 ********************************************************************/
29 char* smb_io_utime(BOOL io, UTIME *t, char *q, char *base, int align, int depth)
31 if (t == NULL) return NULL;
33 DEBUG(5,("%s%04x smb_io_utime\n", tab_depth(depth), PTR_DIFF(q, base)));
34 depth++;
36 q = align_offset(q, base, align);
38 DBG_RW_IVAL ("time", depth, base, io, q, t->time); q += 4;
40 return q;
43 /*******************************************************************
44 reads or writes an NTTIME structure.
45 ********************************************************************/
46 char* smb_io_time(BOOL io, NTTIME *nttime, char *q, char *base, int align, int depth)
48 if (nttime == NULL) return NULL;
50 DEBUG(5,("%s%04x smb_io_time\n", tab_depth(depth), PTR_DIFF(q, base)));
51 depth++;
53 q = align_offset(q, base, align);
55 DBG_RW_IVAL("low ", depth, base, io, q, nttime->low ); q += 4; /* low part */
56 DBG_RW_IVAL("high", depth, base, io, q, nttime->high); q += 4; /* high part */
58 return q;
61 /*******************************************************************
62 creates a DOM_SID structure.
64 BIG NOTE: this function only does SIDS where the identauth is not >= 2^32
65 identauth >= 2^32 can be detected because it will be specified in hex
67 ********************************************************************/
68 void make_dom_sid(DOM_SID *sid, char *domsid)
70 int identauth;
71 char *p;
73 if (sid == NULL) return;
75 if (domsid == NULL)
77 DEBUG(4,("netlogon domain SID: none\n"));
78 sid->sid_rev_num = 0;
79 sid->num_auths = 0;
80 return;
83 DEBUG(4,("netlogon domain SID: %s\n", domsid));
85 /* assume, but should check, that domsid starts "S-" */
86 p = strtok(domsid+2,"-");
87 sid->sid_rev_num = atoi(p);
89 /* identauth in decimal should be < 2^32 */
90 /* identauth in hex should be >= 2^32 */
91 identauth = atoi(strtok(0,"-"));
93 DEBUG(4,("netlogon rev %d\n", sid->sid_rev_num));
94 DEBUG(4,("netlogon %s ia %d\n", p, identauth));
96 sid->id_auth[0] = 0;
97 sid->id_auth[1] = 0;
98 sid->id_auth[2] = (identauth & 0xff000000) >> 24;
99 sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
100 sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
101 sid->id_auth[5] = (identauth & 0x000000ff);
103 sid->num_auths = 0;
105 while ((p = strtok(0, "-")) != NULL)
107 sid->sub_auths[sid->num_auths++] = atoi(p);
111 /*******************************************************************
112 reads or writes a DOM_SID structure.
113 ********************************************************************/
114 char* smb_io_dom_sid(BOOL io, DOM_SID *sid, char *q, char *base, int align, int depth)
116 int i;
118 if (sid == NULL) return NULL;
120 DEBUG(5,("%s%04x smb_io_dom_sid\n", tab_depth(depth), PTR_DIFF(q, base)));
121 depth++;
123 q = align_offset(q, base, align);
125 DBG_RW_IVAL("num_auths ", depth, base, io, q, sid->num_auths); q += 4;
126 DBG_RW_CVAL("sid_rev_num", depth, base, io, q, sid->sid_rev_num); q++;
127 DBG_RW_CVAL("num_auths ", depth, base, io, q, sid->num_auths); q++;
129 for (i = 0; i < 6; i++)
131 fstring tmp;
132 sprintf(tmp, "id_auth[%d] ", i);
133 DBG_RW_CVAL(tmp, depth, base, io, q, sid->id_auth[i]); q++;
136 /* oops! XXXX should really issue a warning here... */
137 if (sid->num_auths > MAXSUBAUTHS) sid->num_auths = MAXSUBAUTHS;
139 DBG_RW_PIVAL(False, "sub_auths ", depth, base, io, q, sid->sub_auths, sid->num_auths); q += sid->num_auths * 4;
141 return q;
144 /*******************************************************************
145 creates a UNIHDR structure.
146 ********************************************************************/
147 void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate)
149 hdr->uni_max_len = 2 * max_len;
150 hdr->uni_str_len = 2 * len;
151 hdr->undoc = terminate;
154 /*******************************************************************
155 reads or writes a UNIHDR structure.
156 ********************************************************************/
157 char* smb_io_unihdr(BOOL io, UNIHDR *hdr, char *q, char *base, int align, int depth)
159 if (hdr == NULL) return NULL;
161 DEBUG(5,("%s%04x smb_io_unihdr\n", tab_depth(depth), PTR_DIFF(q, base)));
162 depth++;
164 q = align_offset(q, base, align);
166 DBG_RW_SVAL("uni_str_len", depth, base, io, q, hdr->uni_str_len); q += 2;
167 DBG_RW_SVAL("uni_max_len", depth, base, io, q, hdr->uni_max_len); q += 2;
168 DBG_RW_IVAL("undoc ", depth, base, io, q, hdr->undoc ); q += 4;
170 /* oops! XXXX maybe issue a warning that this is happening... */
171 if (hdr->uni_max_len > MAX_UNISTRLEN) hdr->uni_max_len = MAX_UNISTRLEN;
172 if (hdr->uni_str_len > MAX_UNISTRLEN) hdr->uni_str_len = MAX_UNISTRLEN;
174 return q;
177 /*******************************************************************
178 creates a UNIHDR2 structure.
179 ********************************************************************/
180 void make_uni_hdr2(UNIHDR2 *hdr, int max_len, int len, uint16 terminate)
182 make_uni_hdr(&(hdr->unihdr), max_len, len, terminate);
183 hdr->undoc_buffer = len > 0 ? 1 : 0;
186 /*******************************************************************
187 reads or writes a UNIHDR2 structure.
188 ********************************************************************/
189 char* smb_io_unihdr2(BOOL io, UNIHDR2 *hdr2, char *q, char *base, int align, int depth)
191 if (hdr2 == NULL) return NULL;
193 DEBUG(5,("%s%04x smb_io_unihdr2\n", tab_depth(depth), PTR_DIFF(q, base)));
194 depth++;
196 q = align_offset(q, base, align);
198 q = smb_io_unihdr(io, &(hdr2->unihdr), q, base, align, depth);
199 DBG_RW_IVAL("undoc_buffer", depth, base, io, q, hdr2->undoc_buffer); q += 4;
201 return q;
204 /*******************************************************************
205 creates a UNISTR structure.
206 ********************************************************************/
207 void make_unistr(UNISTR *str, char *buf)
209 /* store the string (null-terminated copy) */
210 PutUniCode((char *)(str->buffer), buf);
213 /*******************************************************************
214 reads or writes a UNISTR structure.
215 XXXX NOTE: UNISTR structures NEED to be null-terminated.
216 ********************************************************************/
217 char* smb_io_unistr(BOOL io, UNISTR *uni, char *q, char *base, int align, int depth)
219 if (uni == NULL) return NULL;
221 DEBUG(5,("%s%04x smb_io_unistr\n", tab_depth(depth), PTR_DIFF(q, base)));
222 depth++;
224 q = align_offset(q, base, align);
226 if (io)
228 /* io True indicates read _from_ the SMB buffer into the string */
229 q += 2 * unistrcpy((char*)uni->buffer, q);
231 else
233 /* io True indicates copy _from_ the string into SMB buffer */
234 q += 2 * unistrcpy(q, (char*)uni->buffer);
236 return q;
239 /*******************************************************************
240 creates a UNISTR2 structure.
241 ********************************************************************/
242 void make_unistr2(UNISTR2 *str, char *buf, int len)
244 /* set up string lengths. add one if string is not null-terminated */
245 str->uni_max_len = len;
246 str->undoc = 0;
247 str->uni_str_len = len;
249 /* store the string (null-terminated copy) */
250 PutUniCode((char *)str->buffer, buf);
253 /*******************************************************************
254 reads or writes a UNISTR2 structure.
255 XXXX NOTE: UNISTR2 structures need NOT be null-terminated.
256 the uni_str_len member tells you how long the string is;
257 the uni_max_len member tells you how large the buffer is.
258 ********************************************************************/
259 char* smb_io_unistr2(BOOL io, UNISTR2 *uni2, char *q, char *base, int align, int depth)
261 if (uni2 == NULL) return NULL;
263 DEBUG(5,("%s%04x smb_io_unistr2\n", tab_depth(depth), PTR_DIFF(q, base)));
264 depth++;
266 q = align_offset(q, base, align);
268 /* should be value 0, so enforce it. */
269 uni2->undoc = 0;
271 DBG_RW_IVAL("uni_max_len", depth, base, io, q, uni2->uni_max_len); q += 4;
272 DBG_RW_IVAL("undoc ", depth, base, io, q, uni2->undoc ); q += 4;
273 DBG_RW_IVAL("uni_str_len", depth, base, io, q, uni2->uni_str_len); q += 4;
275 /* oops! XXXX maybe issue a warning that this is happening... */
276 if (uni2->uni_max_len > MAX_UNISTRLEN) uni2->uni_max_len = MAX_UNISTRLEN;
277 if (uni2->uni_str_len > MAX_UNISTRLEN) uni2->uni_str_len = MAX_UNISTRLEN;
279 /* buffer advanced by indicated length of string
280 NOT by searching for null-termination */
281 DBG_RW_PSVAL(True, "buffer ", depth, base, io, q, uni2->buffer, uni2->uni_max_len); q += uni2->uni_max_len * 2;
283 return q;
286 /*******************************************************************
287 creates a DOM_SID2 structure.
288 ********************************************************************/
289 void make_dom_sid2(DOM_SID2 *sid2, char *sid_str)
291 int len_sid_str = strlen(sid_str);
293 sid2->type = 0x5;
294 sid2->undoc = 0;
295 make_uni_hdr2(&(sid2->hdr), len_sid_str, len_sid_str, 0);
296 make_unistr (&(sid2->str), sid_str);
299 /*******************************************************************
300 reads or writes a DOM_SID2 structure.
301 ********************************************************************/
302 char* smb_io_dom_sid2(BOOL io, DOM_SID2 *sid2, char *q, char *base, int align, int depth)
304 if (sid2 == NULL) return NULL;
306 DEBUG(5,("%s%04x smb_io_dom_sid2\n", tab_depth(depth), PTR_DIFF(q, base)));
307 depth++;
309 q = align_offset(q, base, align);
311 /* should be value 5, so enforce it */
312 sid2->type = 5;
314 /* should be value 0, so enforce it */
315 sid2->undoc = 0;
317 DBG_RW_IVAL("type ", depth, base, io, q, sid2->type ); q += 4;
318 DBG_RW_IVAL("undoc", depth, base, io, q, sid2->undoc); q += 4;
320 q = smb_io_unihdr2(io, &(sid2->hdr), q, base, align, depth);
321 q = smb_io_unistr (io, &(sid2->str), q, base, align, depth);
323 return q;
326 /*******************************************************************
327 creates a DOM_RID2 structure.
328 ********************************************************************/
329 void make_dom_rid2(DOM_RID2 *rid2, uint32 rid)
331 rid2->type = 0x5;
332 rid2->undoc = 0x5;
333 rid2->rid = rid;
334 rid2->rid_idx = 0;
337 /*******************************************************************
338 reads or writes a DOM_RID2 structure.
339 ********************************************************************/
340 char* smb_io_dom_rid2(BOOL io, DOM_RID2 *rid2, char *q, char *base, int align, int depth)
342 if (rid2 == NULL) return NULL;
344 DEBUG(5,("%s%04x smb_io_dom_rid2\n", tab_depth(depth), PTR_DIFF(q, base)));
345 depth++;
347 q = align_offset(q, base, align);
349 /* should be value 5, so enforce it */
350 rid2->type = 5;
352 /* should be value 5, so enforce it */
353 rid2->undoc = 5;
355 DBG_RW_IVAL("type ", depth, base, io, q, rid2->type); q += 4;
356 DBG_RW_IVAL("undoc ", depth, base, io, q, rid2->undoc ); q += 4;
357 DBG_RW_IVAL("rid ", depth, base, io, q, rid2->rid ); q += 4;
358 DBG_RW_IVAL("rid_idx", depth, base, io, q, rid2->rid_idx ); q += 4;
360 return q;
363 /*******************************************************************
364 makes a DOM_CLNT_SRV structure.
365 ********************************************************************/
366 void make_clnt_srv(DOM_CLNT_SRV *log, char *logon_srv, char *comp_name)
368 if (log == NULL) return;
370 DEBUG(5,("make_clnt_srv: %d\n", __LINE__));
372 if (logon_srv != NULL)
374 log->undoc_buffer = 1;
375 make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
377 else
379 log->undoc_buffer = 1;
382 if (comp_name != NULL)
384 log->undoc_buffer2 = 1;
385 make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
387 else
389 log->undoc_buffer2 = 1;
393 /*******************************************************************
394 reads or writes a DOM_CLNT_SRV structure.
395 ********************************************************************/
396 char* smb_io_clnt_srv(BOOL io, DOM_CLNT_SRV *log, char *q, char *base, int align, int depth)
398 if (log == NULL) return NULL;
400 DEBUG(5,("%s%04x smb_io_clnt_srv\n", tab_depth(depth), PTR_DIFF(q, base)));
401 depth++;
403 q = align_offset(q, base, align);
405 DBG_RW_IVAL("undoc_buffer ", depth, base, io, q, log->undoc_buffer ); q += 4;
406 q = smb_io_unistr2(io, &(log->uni_logon_srv), q, base, align, depth);
408 DBG_RW_IVAL("undoc_buffer2", depth, base, io, q, log->undoc_buffer2); q += 4;
409 q = smb_io_unistr2(io, &(log->uni_comp_name), q, base, align, depth);
411 return q;
414 /*******************************************************************
415 makes a DOM_LOG_INFO structure.
416 ********************************************************************/
417 void make_log_info(DOM_LOG_INFO *log, char *logon_srv, char *acct_name,
418 uint16 sec_chan, char *comp_name)
420 if (log == NULL) return;
422 DEBUG(5,("make_log_info %d\n", __LINE__));
424 log->undoc_buffer = 1;
426 make_unistr2(&(log->uni_logon_srv), logon_srv, strlen(logon_srv));
427 make_unistr2(&(log->uni_acct_name), acct_name, strlen(acct_name));
429 log->sec_chan = sec_chan;
431 make_unistr2(&(log->uni_comp_name), comp_name, strlen(comp_name));
434 /*******************************************************************
435 reads or writes a DOM_LOG_INFO structure.
436 ********************************************************************/
437 char* smb_io_log_info(BOOL io, DOM_LOG_INFO *log, char *q, char *base, int align, int depth)
439 if (log == NULL) return NULL;
441 DEBUG(5,("%s%04x smb_io_log_info\n", tab_depth(depth), PTR_DIFF(q, base)));
442 depth++;
444 q = align_offset(q, base, align);
446 DBG_RW_IVAL("undoc_buffer", depth, base, io, q, log->undoc_buffer); q += 4;
448 q = smb_io_unistr2(io, &(log->uni_logon_srv), q, base, align, depth);
449 q = smb_io_unistr2(io, &(log->uni_acct_name), q, base, align, depth);
451 DBG_RW_SVAL("sec_chan", depth, base, io, q, log->sec_chan); q += 2;
453 q = smb_io_unistr2(io, &(log->uni_comp_name), q, base, align, depth);
455 return q;
458 /*******************************************************************
459 reads or writes a DOM_CHAL structure.
460 ********************************************************************/
461 char* smb_io_chal(BOOL io, DOM_CHAL *chal, char *q, char *base, int align, int depth)
463 if (chal == NULL) return NULL;
465 DEBUG(5,("%s%04x smb_io_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
466 depth++;
468 q = align_offset(q, base, align);
470 DBG_RW_IVAL("data[0]", depth, base, io, q, chal->data[0]); q += 4;
471 DBG_RW_IVAL("data[1]", depth, base, io, q, chal->data[1]); q += 4;
473 DBG_RW_PCVAL(False, "data", depth, base, io, q, chal->data, 8); q += 8;
475 return q;
478 /*******************************************************************
479 reads or writes a DOM_CRED structure.
480 ********************************************************************/
481 char* smb_io_cred(BOOL io, DOM_CRED *cred, char *q, char *base, int align, int depth)
483 if (cred == NULL) return NULL;
485 DEBUG(5,("%s%04x smb_io_cred\n", tab_depth(depth), PTR_DIFF(q, base)));
486 depth++;
488 q = align_offset(q, base, align);
490 q = smb_io_chal (io, &(cred->challenge), q, base, align, depth);
491 q = smb_io_utime(io, &(cred->timestamp), q, base, align, depth);
493 return q;
496 /*******************************************************************
497 makes a DOM_CLNT_INFO2 structure.
498 ********************************************************************/
499 void make_clnt_info2(DOM_CLNT_INFO2 *clnt,
500 char *logon_srv, char *comp_name,
501 DOM_CRED *clnt_cred)
503 if (clnt == NULL) return;
505 DEBUG(5,("make_clnt_info: %d\n", __LINE__));
507 make_clnt_srv(&(clnt->login), logon_srv, comp_name);
509 if (clnt_cred != NULL)
511 clnt->ptr_cred = 1;
512 memcpy(&(clnt->cred), clnt_cred, sizeof(clnt->cred));
514 else
516 clnt->ptr_cred = 0;
520 /*******************************************************************
521 reads or writes a DOM_CLNT_INFO2 structure.
522 ********************************************************************/
523 char* smb_io_clnt_info2(BOOL io, DOM_CLNT_INFO2 *clnt, char *q, char *base, int align, int depth)
525 if (clnt == NULL) return NULL;
527 DEBUG(5,("%s%04x smb_io_clnt_info2\n", tab_depth(depth), PTR_DIFF(q, base)));
528 depth++;
530 q = align_offset(q, base, align);
532 q = smb_io_clnt_srv(io, &(clnt->login), q, base, align, depth);
534 q = align_offset(q, base, align);
536 DBG_RW_IVAL("ptr_cred", depth, base, io, q, clnt->ptr_cred); q += 4;
537 q = smb_io_cred (io, &(clnt->cred ), q, base, align, depth);
539 return q;
542 /*******************************************************************
543 reads or writes a DOM_CLNT_INFO structure.
544 ********************************************************************/
545 char* smb_io_clnt_info(BOOL io, DOM_CLNT_INFO *clnt, char *q, char *base, int align, int depth)
547 if (clnt == NULL) return NULL;
549 DEBUG(5,("%s%04x smb_io_clnt_info\n", tab_depth(depth), PTR_DIFF(q, base)));
550 depth++;
552 q = align_offset(q, base, align);
554 q = smb_io_log_info(io, &(clnt->login), q, base, align, depth);
555 q = smb_io_cred (io, &(clnt->cred ), q, base, align, depth);
557 return q;
560 /*******************************************************************
561 makes a DOM_LOGON_ID structure.
562 ********************************************************************/
563 void make_logon_id(DOM_LOGON_ID *log, uint32 log_id_low, uint32 log_id_high)
565 if (log == NULL) return;
567 DEBUG(5,("make_logon_id: %d\n", __LINE__));
569 log->low = log_id_low;
570 log->high = log_id_high;
573 /*******************************************************************
574 reads or writes a DOM_LOGON_ID structure.
575 ********************************************************************/
576 char* smb_io_logon_id(BOOL io, DOM_LOGON_ID *log, char *q, char *base, int align, int depth)
578 if (log == NULL) return NULL;
580 DEBUG(5,("%s%04x smb_io_logon_id\n", tab_depth(depth), PTR_DIFF(q, base)));
581 depth++;
583 q = align_offset(q, base, align);
585 DBG_RW_IVAL("low ", depth, base, io, q, log->low ); q += 4;
586 DBG_RW_IVAL("high", depth, base, io, q, log->high); q += 4;
588 return q;
591 /*******************************************************************
592 makes an ARC4_OWF structure.
593 ********************************************************************/
594 void make_arc4_owf(ARC4_OWF *hash, char data[16])
596 if (hash == NULL) return;
598 DEBUG(5,("make_arc4_owf: %d\n", __LINE__));
600 if (data != NULL)
602 memcpy(hash->data, data, sizeof(hash->data));
604 else
606 bzero(hash->data, sizeof(hash->data));
610 /*******************************************************************
611 reads or writes an ARC4_OWF structure.
612 ********************************************************************/
613 char* smb_io_arc4_owf(BOOL io, ARC4_OWF *hash, char *q, char *base, int align, int depth)
615 if (hash == NULL) return NULL;
617 DEBUG(5,("%s%04x smb_io_arc4_owf\n", tab_depth(depth), PTR_DIFF(q, base)));
618 depth++;
620 q = align_offset(q, base, align);
622 DBG_RW_PCVAL(False, "data", depth, base, io, q, hash->data, 16); q += 16;
624 return q;
627 /*******************************************************************
628 makes a DOM_ID_INFO_1 structure.
629 ********************************************************************/
630 void make_id_info1(DOM_ID_INFO_1 *id, char *domain_name,
631 uint32 param_ctrl, uint32 log_id_low, uint32 log_id_high,
632 char *user_name, char *wksta_name,
633 char arc4_lm_owf[16], char arc4_nt_owf[16])
635 int len_domain_name = strlen(domain_name);
636 int len_user_name = strlen(user_name );
637 int len_wksta_name = strlen(wksta_name );
639 if (id == NULL) return;
641 DEBUG(5,("make_id_info1: %d\n", __LINE__));
643 id->ptr_id_info1 = 1;
645 make_uni_hdr(&(id->hdr_domain_name), len_domain_name, len_domain_name, 4);
647 id->param_ctrl = param_ctrl;
648 make_logon_id(&(id->logon_id), log_id_low, log_id_high);
650 make_uni_hdr(&(id->hdr_user_name ), len_user_name , len_user_name , 4);
651 make_uni_hdr(&(id->hdr_wksta_name ), len_wksta_name , len_wksta_name , 4);
653 make_arc4_owf(&(id->arc4_lm_owf), arc4_lm_owf);
654 make_arc4_owf(&(id->arc4_nt_owf), arc4_nt_owf);
656 make_unistr2(&(id->uni_domain_name), domain_name, len_domain_name);
657 make_unistr2(&(id->uni_user_name ), user_name , len_user_name );
658 make_unistr2(&(id->uni_wksta_name ), wksta_name , len_wksta_name );
661 /*******************************************************************
662 reads or writes an DOM_ID_INFO_1 structure.
663 ********************************************************************/
664 char* smb_io_id_info1(BOOL io, DOM_ID_INFO_1 *id, char *q, char *base, int align, int depth)
666 if (id == NULL) return NULL;
668 DEBUG(5,("%s%04x smb_io_id_info1\n", tab_depth(depth), PTR_DIFF(q, base)));
669 depth++;
671 q = align_offset(q, base, align);
673 DBG_RW_IVAL("ptr_id_info1", depth, base, io, q, id->ptr_id_info1); q += 4;
675 if (id->ptr_id_info1 != 0)
677 q = smb_io_unihdr(io, &(id->hdr_domain_name), q, base, align, depth);
679 DBG_RW_IVAL("param_ctrl", depth, base, io, q, id->param_ctrl); q += 4;
680 q = smb_io_logon_id(io, &(id->logon_id), q, base, align, depth);
682 q = smb_io_unihdr(io, &(id->hdr_user_name ), q, base, align, depth);
683 q = smb_io_unihdr(io, &(id->hdr_wksta_name ), q, base, align, depth);
685 q = smb_io_arc4_owf(io, &(id->arc4_lm_owf), q, base, align, depth);
686 q = smb_io_arc4_owf(io, &(id->arc4_nt_owf), q, base, align, depth);
688 q = smb_io_unistr2(io, &(id->uni_domain_name), q, base, align, depth);
689 q = smb_io_unistr2(io, &(id->uni_user_name ), q, base, align, depth);
690 q = smb_io_unistr2(io, &(id->uni_wksta_name ), q, base, align, depth);
693 return q;
696 /*******************************************************************
697 makes a DOM_SAM_INFO structure.
698 ********************************************************************/
699 void make_sam_info(DOM_SAM_INFO *sam,
700 char *logon_srv, char *comp_name, DOM_CRED *clnt_cred,
701 DOM_CRED *rtn_cred, uint16 logon_level, uint16 switch_value,
702 DOM_ID_INFO_1 *id1)
704 if (sam == NULL) return;
706 DEBUG(5,("make_sam_info: %d\n", __LINE__));
708 make_clnt_info2(&(sam->client), logon_srv, comp_name, clnt_cred);
710 if (rtn_cred != NULL)
712 sam->ptr_rtn_cred = 1;
713 memcpy(&(sam->rtn_cred), rtn_cred, sizeof(sam->rtn_cred));
715 else
717 sam->ptr_rtn_cred = 0;
720 sam->logon_level = logon_level;
721 sam->switch_value = switch_value;
723 switch (sam->switch_value)
725 case 1:
727 sam->auth.id1 = id1;
728 break;
730 default:
732 /* PANIC! */
733 DEBUG(4,("make_sam_info: unknown switch_value!\n"));
734 break;
739 /*******************************************************************
740 reads or writes a DOM_SAM_INFO structure.
741 ********************************************************************/
742 char* smb_io_sam_info(BOOL io, DOM_SAM_INFO *sam, char *q, char *base, int align, int depth)
744 if (sam == NULL) return NULL;
746 DEBUG(5,("%s%04x smb_io_sam_info\n", tab_depth(depth), PTR_DIFF(q, base)));
747 depth++;
749 q = align_offset(q, base, align);
751 q = smb_io_clnt_info2(io, &(sam->client ), q, base, align, depth);
753 DBG_RW_IVAL("ptr_rtn_cred", depth, base, io, q, sam->ptr_rtn_cred); q += 4;
754 q = smb_io_cred (io, &(sam->rtn_cred), q, base, align, depth);
756 DBG_RW_SVAL("logon_level ", depth, base, io, q, sam->logon_level); q += 2;
757 DBG_RW_SVAL("switch_value", depth, base, io, q, sam->switch_value); q += 2;
759 switch (sam->switch_value)
761 case 1:
763 q = smb_io_id_info1(io, sam->auth.id1, q, base, align, depth);
764 break;
766 default:
768 /* PANIC! */
769 DEBUG(4,("smb_io_sam_info: unknown switch_value!\n"));
770 break;
773 return q;
776 /*******************************************************************
777 reads or writes a DOM_GID structure.
778 ********************************************************************/
779 char* smb_io_gid(BOOL io, DOM_GID *gid, char *q, char *base, int align, int depth)
781 if (gid == NULL) return NULL;
783 DEBUG(5,("%s%04x smb_io_gid\n", tab_depth(depth), PTR_DIFF(q, base)));
784 depth++;
786 q = align_offset(q, base, align);
788 DBG_RW_IVAL("g_rid", depth, base, io, q, gid->g_rid); q += 4;
789 DBG_RW_IVAL("attr ", depth, base, io, q, gid->attr ); q += 4;
791 return q;
794 /*******************************************************************
795 creates an RPC_HDR structure.
796 ********************************************************************/
797 void make_rpc_hdr(RPC_HDR *hdr, enum RPC_PKT_TYPE pkt_type, uint8 frag,
798 uint32 call_id, int data_len)
800 if (hdr == NULL) return;
802 hdr->major = 5; /* RPC version 5 */
803 hdr->minor = 0; /* minor version 0 */
804 hdr->pkt_type = pkt_type; /* RPC packet type */
805 hdr->frag = frag; /* first frag + last frag */
806 hdr->pack_type = 0x10; /* packed data representation */
807 hdr->frag_len = data_len; /* fragment length, fill in later */
808 hdr->auth_len = 0; /* authentication length */
809 hdr->call_id = call_id; /* call identifier - match incoming RPC */
812 /*******************************************************************
813 reads or writes an RPC_HDR structure.
814 ********************************************************************/
815 char* smb_io_rpc_hdr(BOOL io, RPC_HDR *rpc, char *q, char *base, int align, int depth)
817 if (rpc == NULL) return NULL;
819 DEBUG(5,("%s%04x smb_io_rpc_hdr\n", tab_depth(depth), PTR_DIFF(q, base)));
820 depth++;
822 DBG_RW_CVAL("major ", depth, base, io, q, rpc->major); q++;
823 DBG_RW_CVAL("minor ", depth, base, io, q, rpc->minor); q++;
824 DBG_RW_CVAL("pkt_type ", depth, base, io, q, rpc->pkt_type); q++;
825 DBG_RW_CVAL("frag ", depth, base, io, q, rpc->frag); q++;
826 DBG_RW_IVAL("pack_type ", depth, base, io, q, rpc->pack_type); q += 4;
827 DBG_RW_SVAL("frag_len ", depth, base, io, q, rpc->frag_len); q += 2;
828 DBG_RW_SVAL("auth_len ", depth, base, io, q, rpc->auth_len); q += 2;
829 DBG_RW_IVAL("call_id ", depth, base, io, q, rpc->call_id); q += 4;
831 return q;
834 /*******************************************************************
835 creates an RPC_IFACE structure.
836 ********************************************************************/
837 void make_rpc_iface(RPC_IFACE *ifc, char data[16], uint32 version)
839 if (ifc == NULL || data == NULL) return;
841 memcpy(ifc->data, data, sizeof(ifc->data)); /* 16 bytes of number */
842 ifc->version = version; /* the interface number */
845 /*******************************************************************
846 reads or writes an RPC_IFACE structure.
847 ********************************************************************/
848 char* smb_io_rpc_iface(BOOL io, RPC_IFACE *ifc, char *q, char *base, int align, int depth)
850 if (ifc == NULL) return NULL;
852 DEBUG(5,("%s%04x smb_io_rpc_iface\n", tab_depth(depth), PTR_DIFF(q, base)));
853 depth++;
855 q = align_offset(q, base, align);
857 DBG_RW_PCVAL(False, "data ", depth, base, io, q, ifc->data, sizeof(ifc->data)); q += sizeof(ifc->data);
858 DBG_RW_IVAL ( "version", depth, base, io, q, ifc->version); q += 4;
860 return q;
863 /*******************************************************************
864 creates an RPC_ADDR_STR structure.
865 ********************************************************************/
866 void make_rpc_addr_str(RPC_ADDR_STR *str, char *name)
868 if (str == NULL || name == NULL) return;
870 str->len = strlen(name) + 1;
871 fstrcpy(str->addr, name);
874 /*******************************************************************
875 reads or writes an RPC_ADDR_STR structure.
876 ********************************************************************/
877 char* smb_io_rpc_addr_str(BOOL io, RPC_ADDR_STR *str, char *q, char *base, int align, int depth)
879 if (str == NULL) return NULL;
881 DEBUG(5,("%s%04x smb_io_rpc_addr_str\n", tab_depth(depth), PTR_DIFF(q, base)));
882 depth++;
884 q = align_offset(q, base, align);
886 DBG_RW_IVAL ( "len ", depth, base, io, q, str->len); q += 2;
887 DBG_RW_PCVAL(True, "addr", depth, base, io, q, str->addr, str->len); q += str->len;
889 return q;
892 /*******************************************************************
893 creates an RPC_HDR_BBA structure.
894 ********************************************************************/
895 void make_rpc_hdr_bba(RPC_HDR_BBA *bba, uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid)
897 if (bba == NULL) return;
899 bba->max_tsize = max_tsize; /* maximum transmission fragment size (0x1630) */
900 bba->max_rsize = max_rsize; /* max receive fragment size (0x1630) */
901 bba->assoc_gid = assoc_gid; /* associated group id (0x0) */
904 /*******************************************************************
905 reads or writes an RPC_HDR_BBA structure.
906 ********************************************************************/
907 char* smb_io_rpc_hdr_bba(BOOL io, RPC_HDR_BBA *rpc, char *q, char *base, int align, int depth)
909 if (rpc == NULL) return NULL;
911 DEBUG(5,("%s%04x smb_io_rpc_hdr_bba\n", tab_depth(depth), PTR_DIFF(q, base)));
912 depth++;
914 DBG_RW_SVAL("max_tsize", depth, base, io, q, rpc->max_tsize); q += 2;
915 DBG_RW_SVAL("max_rsize", depth, base, io, q, rpc->max_rsize); q += 2;
916 DBG_RW_IVAL("assoc_gid", depth, base, io, q, rpc->assoc_gid); q += 4;
918 return q;
921 /*******************************************************************
922 creates an RPC_HDR_RB structure.
923 ********************************************************************/
924 void make_rpc_hdr_rb(RPC_HDR_RB *rpc,
925 uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
926 uint32 num_elements, uint16 context_id, uint8 num_syntaxes,
927 RPC_IFACE *abstract, RPC_IFACE *transfer)
929 if (rpc == NULL) return;
931 make_rpc_hdr_bba(&(rpc->bba), max_tsize, max_rsize, assoc_gid);
933 rpc->num_elements = num_elements ; /* the number of elements (0x1) */
934 rpc->context_id = context_id ; /* presentation context identifier (0x0) */
935 rpc->num_syntaxes = num_syntaxes ; /* the number of syntaxes (has always been 1?)(0x1) */
937 /* num and vers. of interface client is using */
938 memcpy(&(rpc->abstract), abstract, sizeof(rpc->abstract));
940 /* num and vers. of interface to use for replies */
941 memcpy(&(rpc->transfer), transfer, sizeof(rpc->transfer));
944 /*******************************************************************
945 reads or writes an RPC_HDR_RB structure.
946 ********************************************************************/
947 char* smb_io_rpc_hdr_rb(BOOL io, RPC_HDR_RB *rpc, char *q, char *base, int align, int depth)
949 if (rpc == NULL) return NULL;
951 DEBUG(5,("%s%04x smb_io_rpc_hdr_bba\n", tab_depth(depth), PTR_DIFF(q, base)));
952 depth++;
954 q = smb_io_rpc_hdr_bba(io, &(rpc->bba), q, base, align, depth);
956 DBG_RW_IVAL("num_elements", depth, base, io, q, rpc->num_elements); q += 4;
957 DBG_RW_IVAL("context_id ", depth, base, io, q, rpc->context_id ); q += 4;
958 DBG_RW_IVAL("num_syntaxes", depth, base, io, q, rpc->num_syntaxes); q += 4;
960 q = smb_io_rpc_iface(io, &(rpc->abstract), q, base, align, depth);
961 q = smb_io_rpc_iface(io, &(rpc->transfer), q, base, align, depth);
963 return q;
966 /*******************************************************************
967 creates an RPC_RESULTS structure.
969 lkclXXXX only one reason at the moment!
971 ********************************************************************/
972 void make_rpc_results(RPC_RESULTS *res,
973 uint8 num_results, uint16 result, uint16 reason)
975 if (res == NULL) return;
977 res->num_results = num_results; /* the number of results (0x01) */
978 res->result = result ; /* result (0x00 = accept) */
979 res->reason = reason ; /* reason (0x00 = no reason specified) */
982 /*******************************************************************
983 reads or writes an RPC_RESULTS structure.
985 lkclXXXX only one reason at the moment!
987 ********************************************************************/
988 char* smb_io_rpc_results(BOOL io, RPC_RESULTS *res, char *q, char *base, int align, int depth)
990 if (res == NULL) return NULL;
992 DEBUG(5,("%s%04x smb_io_rpc_results\n", tab_depth(depth), PTR_DIFF(q, base)));
993 depth++;
995 q = align_offset(q, base, align);
997 DBG_RW_CVAL("num_results", depth, base, io, q, res->num_results); q++;
999 q = align_offset(q, base, align);
1001 DBG_RW_SVAL("result ", depth, base, io, q, res->result ); q += 2;
1002 DBG_RW_SVAL("reason ", depth, base, io, q, res->reason ); q += 2;
1004 return q;
1007 /*******************************************************************
1008 creates an RPC_HDR_BA structure.
1010 lkclXXXX only one reason at the moment!
1012 ********************************************************************/
1013 void make_rpc_hdr_ba(RPC_HDR_BA *rpc,
1014 uint16 max_tsize, uint16 max_rsize, uint32 assoc_gid,
1015 char *pipe_addr,
1016 uint8 num_results, uint16 result, uint16 reason,
1017 RPC_IFACE *transfer)
1019 if (rpc == NULL || transfer == NULL || pipe_addr == NULL) return;
1021 make_rpc_hdr_bba (&(rpc->bba ), max_tsize, max_rsize, assoc_gid);
1022 make_rpc_addr_str(&(rpc->addr), pipe_addr);
1023 make_rpc_results (&(rpc->res ), num_results, result, reason);
1025 /* the transfer syntax from the request */
1026 memcpy(&(rpc->transfer), transfer, sizeof(rpc->transfer));
1029 /*******************************************************************
1030 reads or writes an RPC_HDR_BA structure.
1031 ********************************************************************/
1032 char* smb_io_rpc_hdr_ba(BOOL io, RPC_HDR_BA *rpc, char *q, char *base, int align, int depth)
1034 if (rpc == NULL) return NULL;
1036 DEBUG(5,("%s%04x smb_io_rpc_hdr_ba\n", tab_depth(depth), PTR_DIFF(q, base)));
1037 depth++;
1039 q = smb_io_rpc_hdr_bba (io, &(rpc->bba) , q, base, align, depth);
1040 q = smb_io_rpc_addr_str(io, &(rpc->addr) , q, base, align, depth);
1041 q = smb_io_rpc_results (io, &(rpc->res) , q, base, align, depth);
1042 q = smb_io_rpc_iface (io, &(rpc->transfer), q, base, align, depth);
1044 return q;
1047 /*******************************************************************
1048 makes an LSA_OBJ_ATTR structure.
1049 ********************************************************************/
1050 void make_obj_attr(LSA_OBJ_ATTR *attr, uint32 attributes, uint32 sec_qos)
1052 if (attr == NULL) return;
1054 DEBUG(5,("make_obj_attr\n"));
1056 attr->len = 0x18; /* length of object attribute block, in bytes */
1057 attr->ptr_root_dir = 0;
1058 attr->ptr_obj_name = 0;
1059 attr->attributes = attributes;
1060 attr->ptr_sec_desc = 0;
1061 attr->sec_qos = sec_qos;
1064 /*******************************************************************
1065 reads or writes an LSA_OBJ_ATTR structure.
1066 ********************************************************************/
1067 char* smb_io_obj_attr(BOOL io, LSA_OBJ_ATTR *attr, char *q, char *base, int align, int depth)
1069 char *start;
1071 if (attr == NULL) return NULL;
1073 DEBUG(5,("%s%04x smb_io_obj_attr\n", tab_depth(depth), PTR_DIFF(q, base)));
1074 depth++;
1076 q = align_offset(q, base, align);
1078 start = q;
1080 /* these pointers had _better_ be zero, because we don't know
1081 what they point to!
1083 DBG_RW_IVAL("len" , depth, base, io, q, attr->len ); q += 4; /* 0x18 - length (in bytes) inc. the length field. */
1084 DBG_RW_IVAL("ptr_root_dir", depth, base, io, q, attr->ptr_root_dir); q += 4; /* 0 - root directory (pointer) */
1085 DBG_RW_IVAL("ptr_obj_name", depth, base, io, q, attr->ptr_obj_name); q += 4; /* 0 - object name (pointer) */
1086 DBG_RW_IVAL("attributes" , depth, base, io, q, attr->attributes ); q += 4; /* 0 - attributes (undocumented) */
1087 DBG_RW_IVAL("ptr_sec_desc", depth, base, io, q, attr->ptr_sec_desc); q += 4; /* 0 - security descriptior (pointer) */
1088 DBG_RW_IVAL("sec_qos" , depth, base, io, q, attr->sec_qos ); q += 4; /* 0 - security quality of service */
1090 if (attr->len != PTR_DIFF(q, start))
1092 DEBUG(3,("smb_io_obj_attr: length %lx does not match size %lx\n",
1093 attr->len, PTR_DIFF(q, start)));
1096 return q;
1099 /*******************************************************************
1100 creates an RPC_HDR_RR structure.
1101 ********************************************************************/
1102 void make_rpc_hdr_rr(RPC_HDR_RR *hdr, enum RPC_PKT_TYPE pkt_type,
1103 uint32 call_id, int data_len, uint8 opnum)
1105 if (hdr == NULL) return;
1107 /* frag is FIRST_FRAG | LAST_FRAG. lkclXXXX must define these */
1108 make_rpc_hdr(&(hdr->hdr), pkt_type, 0x03, call_id, data_len);
1110 hdr->alloc_hint = data_len - 0x18; /* allocation hint */
1111 hdr->context_id = 0; /* presentation context identifier */
1112 hdr->cancel_count = 0; /* cancel count */
1113 hdr->opnum = opnum; /* opnum */
1116 /*******************************************************************
1117 reads or writes an RPC_HDR_RR structure.
1118 ********************************************************************/
1119 char* smb_io_rpc_hdr_rr(BOOL io, RPC_HDR_RR *rpc, char *q, char *base, int align, int depth)
1121 if (rpc == NULL) return NULL;
1123 DEBUG(5,("%s%04x smb_io_rpc_hdr_rr\n", tab_depth(depth), PTR_DIFF(q, base)));
1124 depth++;
1126 q = smb_io_rpc_hdr(io, &(rpc->hdr), q, base, align, depth);
1128 DBG_RW_IVAL("alloc_hint", depth, base, io, q, rpc->alloc_hint); q += 4;
1129 DBG_RW_CVAL("context_id", depth, base, io, q, rpc->context_id); q++;
1130 DBG_RW_CVAL("cancel_ct ", depth, base, io, q, rpc->cancel_count); q++;
1131 DBG_RW_CVAL("opnum ", depth, base, io, q, rpc->opnum); q++;
1133 return q;
1135 /*******************************************************************
1136 reads or writes an LSA_POL_HND structure.
1137 ********************************************************************/
1138 char* smb_io_pol_hnd(BOOL io, LSA_POL_HND *pol, char *q, char *base, int align, int depth)
1140 if (pol == NULL) return NULL;
1142 DEBUG(5,("%s%04x smb_io_pol_hnd\n", tab_depth(depth), PTR_DIFF(q, base)));
1143 depth++;
1145 q = align_offset(q, base, align);
1147 DBG_RW_PCVAL(False, "data", depth, base, io, q, pol->data, POL_HND_SIZE); q += POL_HND_SIZE;
1149 return q;
1152 /*******************************************************************
1153 reads or writes a dom query structure.
1154 ********************************************************************/
1155 char* smb_io_dom_query_3(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth)
1157 return smb_io_dom_query(io, d_q, q, base, align, depth);
1160 /*******************************************************************
1161 reads or writes a dom query structure.
1162 ********************************************************************/
1163 char* smb_io_dom_query_5(BOOL io, DOM_QUERY_3 *d_q, char *q, char *base, int align, int depth)
1165 return smb_io_dom_query(io, d_q, q, base, align, depth);
1168 /*******************************************************************
1169 reads or writes a dom query structure.
1170 ********************************************************************/
1171 char* smb_io_dom_query(BOOL io, DOM_QUERY *d_q, char *q, char *base, int align, int depth)
1173 if (d_q == NULL) return NULL;
1175 DEBUG(5,("%s%04x smb_io_dom_query\n", tab_depth(depth), PTR_DIFF(q, base)));
1176 depth++;
1178 q = align_offset(q, base, align);
1180 DBG_RW_SVAL("uni_dom_max_len", depth, base, io, q, d_q->uni_dom_max_len); q += 2; /* domain name string length * 2 */
1181 DBG_RW_SVAL("uni_dom_str_len", depth, base, io, q, d_q->uni_dom_str_len); q += 2; /* domain name string length * 2 */
1183 DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, d_q->buffer_dom_name); q += 4; /* undocumented domain name string buffer pointer */
1184 DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, d_q->buffer_dom_sid ); q += 4; /* undocumented domain SID string buffer pointer */
1186 if (d_q->buffer_dom_name != 0)
1188 q = smb_io_unistr2(io, &(d_q->uni_domain_name), q, base, align, depth); /* domain name (unicode string) */
1190 if (d_q->buffer_dom_sid != 0)
1192 q = smb_io_dom_sid(io, &(d_q->dom_sid), q, base, align, depth); /* domain SID */
1195 return q;
1198 /*******************************************************************
1199 reads or writes a DOM_R_REF structure.
1200 ********************************************************************/
1201 char* smb_io_dom_r_ref(BOOL io, DOM_R_REF *r_r, char *q, char *base, int align, int depth)
1203 int i;
1205 DEBUG(5,("%s%04x smb_io_dom_r_ref\n", tab_depth(depth), PTR_DIFF(q, base)));
1206 depth++;
1208 if (r_r == NULL) return NULL;
1210 q = align_offset(q, base, align);
1212 DBG_RW_IVAL("undoc_buffer ", depth, base, io, q, r_r->undoc_buffer); q += 4; /* undocumented buffer pointer. */
1213 DBG_RW_IVAL("num_ref_doms_1 ", depth, base, io, q, r_r->num_ref_doms_1); q += 4; /* num referenced domains? */
1214 DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, r_r->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer. */
1215 DBG_RW_IVAL("max_entries ", depth, base, io, q, r_r->max_entries); q += 4; /* 32 - max number of entries */
1216 DBG_RW_IVAL("num_ref_doms_2 ", depth, base, io, q, r_r->num_ref_doms_2); q += 4; /* 4 - num referenced domains? */
1218 q = smb_io_unihdr2(io, &(r_r->hdr_dom_name), q, base, align, depth); /* domain name unicode string header */
1220 for (i = 0; i < r_r->num_ref_doms_1-1; i++)
1222 q = smb_io_unihdr2(io, &(r_r->hdr_ref_dom[i]), q, base, align, depth);
1225 q = smb_io_unistr(io, &(r_r->uni_dom_name), q, base, align, depth); /* domain name unicode string */
1227 for (i = 0; i < r_r->num_ref_doms_2; i++)
1229 q = smb_io_dom_sid(io, &(r_r->ref_dom[i]), q, base, align, depth); /* referenced domain SIDs */
1231 return q;
1234 /*******************************************************************
1235 reads or writes a DOM_NAME structure.
1236 ********************************************************************/
1237 char* smb_io_dom_name(BOOL io, DOM_NAME *name, char *q, char *base, int align, int depth)
1239 if (name == NULL) return NULL;
1241 DEBUG(5,("%s%04x smb_io_dom_name\n", tab_depth(depth), PTR_DIFF(q, base)));
1242 depth++;
1244 q = align_offset(q, base, align);
1246 DBG_RW_IVAL("uni_str_len", depth, base, io, q, name->uni_str_len); q += 4;
1248 /* don't know if len is specified by uni_str_len member... */
1249 /* assume unicode string is unicode-null-terminated, instead */
1251 q = smb_io_unistr(io, &(name->str), q, base, align, depth);
1253 return q;
1257 /*******************************************************************
1258 reads or writes a structure.
1259 ********************************************************************/
1260 char* smb_io_neg_flags(BOOL io, NEG_FLAGS *neg, char *q, char *base, int align, int depth)
1262 if (neg == NULL) return NULL;
1264 DEBUG(5,("%s%04x smb_io_neg_flags\n", tab_depth(depth), PTR_DIFF(q, base)));
1265 depth++;
1267 q = align_offset(q, base, align);
1269 DBG_RW_IVAL("neg_flags", depth, base, io, q, neg->neg_flags); q += 4;
1271 return q;
1275 #if 0
1276 /*******************************************************************
1277 reads or writes a structure.
1278 ********************************************************************/
1279 char* smb_io_(BOOL io, *, char *q, char *base, int align, int depth)
1281 if (== NULL) return NULL;
1283 q = align_offset(q, base, align);
1285 DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
1287 return q;
1289 #endif