1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

blanked out these files, so that if someone does make proto, they don't

interfere with the files in the rpc_pipes/ directory.

andrew doesn't want to lose any cvs history by moving files around, so
he's going to look into that tomorrow.
(This used to be commit 5858cb97f565bb1d6337f3bc350b1f8cdfd4555b)
This commit is contained in:
Luke Leighton 1997-10-30 22:33:59 +00:00
parent 9fc5056a4a
commit e77e5e6ef8
10 changed files with 0 additions and 4906 deletions

View File

@ -1,680 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
Copyright (C) Luke Leighton 1996 - 1997 Paul Ashton 1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
extern int DEBUGLEVEL;
/*******************************************************************
makes an LSA_Q_OPEN_POL structure.
********************************************************************/
void make_q_open_pol(LSA_Q_OPEN_POL *r_q, char *server_name,
uint32 attributes, uint32 sec_qos,
uint16 desired_access)
{
if (r_q == NULL) return;
DEBUG(5,("make_open_pol\n"));
r_q->ptr = 1; /* undocumented pointer */
make_unistr2 (&(r_q->uni_server_name), server_name, strlen(server_name));
make_obj_attr(&(r_q->attr ), attributes, sec_qos);
r_q->des_access = desired_access;
}
/*******************************************************************
reads or writes an LSA_Q_OPEN_POL structure.
********************************************************************/
char* lsa_io_q_open_pol(BOOL io, LSA_Q_OPEN_POL *r_q, char *q, char *base, int align, int depth)
{
if (r_q == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_open_pol\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
DBG_RW_IVAL("ptr ", depth, base, io, q, r_q->ptr ); q += 4;
q = smb_io_unistr2 (io, &(r_q->uni_server_name), q, base, align, depth);
q = smb_io_obj_attr(io, &(r_q->attr ), q, base, align, depth);
DBG_RW_SVAL("des_access", depth, base, io, q, r_q->des_access); q += 2;
return q;
}
/*******************************************************************
reads or writes an LSA_R_OPEN_POL structure.
********************************************************************/
char* lsa_io_r_open_pol(BOOL io, LSA_R_OPEN_POL *r_p, char *q, char *base, int align, int depth)
{
if (r_p == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_open_pol\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = smb_io_pol_hnd(io, &(r_p->pol), q, base, align, depth);
DBG_RW_IVAL("status", depth, base, io, q, r_p->status); q += 4;
return q;
}
/*******************************************************************
makes an LSA_Q_QUERY_INFO structure.
********************************************************************/
void make_q_query(LSA_Q_QUERY_INFO *q_q, LSA_POL_HND *hnd, uint16 info_class)
{
if (q_q == NULL || hnd == NULL) return;
DEBUG(5,("make_q_query\n"));
memcpy(&(q_q->pol), hnd, sizeof(q_q->pol));
q_q->info_class = info_class;
}
/*******************************************************************
reads or writes an LSA_Q_QUERY_INFO structure.
********************************************************************/
char* lsa_io_q_query(BOOL io, LSA_Q_QUERY_INFO *q_q, char *q, char *base, int align, int depth)
{
if (q_q == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_query\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = smb_io_pol_hnd(io, &(q_q->pol), q, base, align, depth);
DBG_RW_SVAL("info_class", depth, base, io, q, q_q->info_class); q += 2;
return q;
}
/*******************************************************************
makes an LSA_Q_CLOSE structure.
********************************************************************/
void make_q_close(LSA_Q_CLOSE *q_c, LSA_POL_HND *hnd)
{
if (q_c == NULL || hnd == NULL) return;
DEBUG(5,("make_q_close\n"));
memcpy(&(q_c->pol), hnd, sizeof(q_c->pol));
}
/*******************************************************************
reads or writes an LSA_Q_CLOSE structure.
********************************************************************/
char* lsa_io_q_close(BOOL io, LSA_Q_CLOSE *q_c, char *q, char *base, int align, int depth)
{
if (q_c == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_close\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = smb_io_pol_hnd(io, &(q_c->pol), q, base, align, depth);
return q;
}
/*******************************************************************
makes an LSA_R_CLOSE structure.
********************************************************************/
void make_r_close(LSA_R_CLOSE *q_r, LSA_POL_HND *hnd)
{
if (q_r == NULL || hnd == NULL) return;
DEBUG(5,("make_r_close\n"));
memcpy(&(q_r->pol), hnd, sizeof(q_r->pol));
}
/*******************************************************************
reads or writes an LSA_R_CLOSE structure.
********************************************************************/
char* lsa_io_r_close(BOOL io, LSA_R_CLOSE *r_c, char *q, char *base, int align, int depth)
{
if (r_c == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_close\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = smb_io_pol_hnd(io, &(r_c->pol), q, base, align, depth);
DBG_RW_IVAL("status", depth, base, io, q, r_c->status); q += 4;
return q;
}
/*******************************************************************
reads or writes an LSA_Q_QUERY_INFO structure.
********************************************************************/
char* lsa_io_r_query(BOOL io, LSA_R_QUERY_INFO *r_q, char *q, char *base, int align, int depth)
{
if (r_q == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_query\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_q->undoc_buffer); q += 4;
if (r_q->undoc_buffer != 0)
{
DBG_RW_SVAL("info_class", depth, base, io, q, r_q->info_class); q += 2;
switch (r_q->info_class)
{
case 3:
{
q = smb_io_dom_query_3(io, &(r_q->dom.id3), q, base, align, depth);
break;
}
case 5:
{
q = smb_io_dom_query_5(io, &(r_q->dom.id3), q, base, align, depth);
break;
}
default:
{
/* PANIC! */
break;
}
}
}
DBG_RW_IVAL("status", depth, base, io, q, r_q->status); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_lookup_sids(BOOL io, LSA_Q_LOOKUP_SIDS *q_s, char *q, char *base, int align, int depth)
{
int i;
if (q_s == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_lookup_sids\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_pol_hnd(io, &(q_s->pol_hnd), q, base, align, depth); /* policy handle */
DBG_RW_IVAL("num_entries ", depth, base, io, q, q_s->num_entries); q += 4;
DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, q_s->buffer_dom_sid); q += 4; /* undocumented domain SID buffer pointer */
DBG_RW_IVAL("buffer_dom_name ", depth, base, io, q, q_s->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer */
for (i = 0; i < q_s->num_entries; i++)
{
fstring temp;
sprintf(temp, "buffer_lookup_sids[%d] ", i);
DBG_RW_IVAL(temp, depth, base, io, q, q_s->buffer_lookup_sids[i]); q += 4; /* undocumented domain SID pointers to be looked up. */
}
for (i = 0; i < q_s->num_entries; i++)
{
q = smb_io_dom_sid(io, &(q_s->dom_sids[i]), q, base, align, depth); /* domain SIDs to be looked up. */
}
DBG_RW_PCVAL(False, "undoc ", depth, base, io, q, q_s->undoc, 16); q += 16; /* completely undocumented 16 bytes */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_lookup_sids(BOOL io, LSA_R_LOOKUP_SIDS *r_s, char *q, char *base, int align, int depth)
{
int i;
if (r_s == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_lookup_sids\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_dom_r_ref(io, &(r_s->dom_ref), q, base, align, depth); /* domain reference info */
DBG_RW_IVAL("num_entries ", depth, base, io, q, r_s->num_entries); q += 4;
DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_s->undoc_buffer); q += 4;
DBG_RW_IVAL("num_entries2", depth, base, io, q, r_s->num_entries2); q += 4;
for (i = 0; i < r_s->num_entries2; i++)
{
q = smb_io_dom_sid2(io, &(r_s->dom_sid[i]), q, base, align, depth); /* domain SIDs being looked up */
}
DBG_RW_IVAL("num_entries3", depth, base, io, q, r_s->num_entries3); q += 4;
DBG_RW_IVAL("status ", depth, base, io, q, r_s->status); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_lookup_rids(BOOL io, LSA_Q_LOOKUP_RIDS *q_r, char *q, char *base, int align, int depth)
{
int i;
if (q_r == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_lookup_rids\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_pol_hnd(io, &(q_r->pol_hnd), q, base, align, depth); /* policy handle */
DBG_RW_IVAL("num_entries ", depth, base, io, q, q_r->num_entries); q += 4;
DBG_RW_IVAL("num_entries2 ", depth, base, io, q, q_r->num_entries2); q += 4;
DBG_RW_IVAL("buffer_dom_sid ", depth, base, io, q, q_r->buffer_dom_sid); q += 4; /* undocumented domain SID buffer pointer */
DBG_RW_IVAL("buffer_dom_name", depth, base, io, q, q_r->buffer_dom_name); q += 4; /* undocumented domain name buffer pointer */
for (i = 0; i < q_r->num_entries; i++)
{
q = smb_io_dom_name(io, &(q_r->lookup_name[i]), q, base, align, depth); /* names to be looked up */
}
DBG_RW_PCVAL(False, "undoc ", depth, base, io, q, q_r->undoc, UNKNOWN_LEN); q += UNKNOWN_LEN; /* completely undocumented bytes of unknown length */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_lookup_rids(BOOL io, LSA_R_LOOKUP_RIDS *r_r, char *q, char *base, int align, int depth)
{
int i;
if (r_r == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_lookup_rids\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_dom_r_ref(io, &(r_r->dom_ref), q, base, align, depth); /* domain reference info */
DBG_RW_IVAL("num_entries ", depth, base, io, q, r_r->num_entries); q += 4;
DBG_RW_IVAL("undoc_buffer", depth, base, io, q, r_r->undoc_buffer); q += 4;
DBG_RW_IVAL("num_entries2", depth, base, io, q, r_r->num_entries2); q += 4;
for (i = 0; i < r_r->num_entries2; i++)
{
q = smb_io_dom_rid2(io, &(r_r->dom_rid[i]), q, base, align, depth); /* domain RIDs being looked up */
}
DBG_RW_IVAL("num_entries3", depth, base, io, q, r_r->num_entries3); q += 4;
DBG_RW_IVAL("status ", depth, base, io, q, r_r->status); q += 4;
return q;
}
/*******************************************************************
makes an LSA_Q_REQ_CHAL structure.
********************************************************************/
void make_q_req_chal(LSA_Q_REQ_CHAL *q_c,
char *logon_srv, char *logon_clnt,
DOM_CHAL *clnt_chal)
{
if (q_c == NULL) return;
DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
q_c->undoc_buffer = 1; /* don't know what this buffer is */
make_unistr2(&(q_c->uni_logon_srv ), logon_srv , strlen(logon_srv ));
make_unistr2(&(q_c->uni_logon_clnt), logon_clnt, strlen(logon_clnt));
memcpy(q_c->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
DEBUG(5,("make_q_req_chal: %d\n", __LINE__));
}
/*******************************************************************
reads or writes an LSA_Q_REQ_CHAL structure.
********************************************************************/
char* lsa_io_q_req_chal(BOOL io, LSA_Q_REQ_CHAL *q_c, char *q, char *base, int align, int depth)
{
if (q_c == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_req_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("undoc_buffer", depth, base, io, q, q_c->undoc_buffer); q += 4;
q = smb_io_unistr2(io, &(q_c->uni_logon_srv), q, base, align, depth); /* logon server unicode string */
q = smb_io_unistr2(io, &(q_c->uni_logon_clnt), q, base, align, depth); /* logon client unicode string */
/* client challenge is _not_ aligned after the unicode strings */
q = smb_io_chal(io, &(q_c->clnt_chal), q, base, 0, depth); /* client challenge */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_req_chal(BOOL io, LSA_R_REQ_CHAL *r_c, char *q, char *base, int align, int depth)
{
if (r_c == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_req_chal\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_chal(io, &(r_c->srv_chal), q, base, align, depth); /* server challenge */
DBG_RW_IVAL("status", depth, base, io, q, r_c->status); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
void make_q_auth_2(LSA_Q_AUTH_2 *q_a,
char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
DOM_CHAL *clnt_chal, uint32 clnt_flgs)
{
if (q_a == NULL) return;
DEBUG(5,("make_q_auth_2: %d\n", __LINE__));
make_log_info(&(q_a->clnt_id), logon_srv, acct_name, sec_chan, comp_name);
memcpy(q_a->clnt_chal.data, clnt_chal->data, sizeof(clnt_chal->data));
q_a->clnt_flgs.neg_flags = clnt_flgs;
DEBUG(5,("make_q_auth_2: %d\n", __LINE__));
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_auth_2(BOOL io, LSA_Q_AUTH_2 *q_a, char *q, char *base, int align, int depth)
{
if (q_a == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_auth_2\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_log_info (io, &(q_a->clnt_id), q, base, align, depth); /* client identification info */
/* client challenge is _not_ aligned */
q = smb_io_chal (io, &(q_a->clnt_chal), q, base, 0, depth); /* client-calculated credentials */
q = smb_io_neg_flags(io, &(q_a->clnt_flgs), q, base, align, depth);
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_auth_2(BOOL io, LSA_R_AUTH_2 *r_a, char *q, char *base, int align, int depth)
{
if (r_a == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_auth_2\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_chal (io, &(r_a->srv_chal), q, base, align, depth); /* server challenge */
q = smb_io_neg_flags(io, &(r_a->srv_flgs), q, base, align, depth);
DBG_RW_IVAL("status", depth, base, io, q, r_a->status); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_srv_pwset(BOOL io, LSA_Q_SRV_PWSET *q_s, char *q, char *base, int align, int depth)
{
if (q_s == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_srv_pwset\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_clnt_info(io, &(q_s->clnt_id), q, base, align, depth); /* client identification/authentication info */
DBG_RW_PCVAL(False, "pwd", depth, base, io, q, q_s->pwd, 16); q += 16; /* new password - undocumented */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_srv_pwset(BOOL io, LSA_R_SRV_PWSET *r_s, char *q, char *base, int align, int depth)
{
if (r_s == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_srv_pwset\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_cred(io, &(r_s->srv_cred), q, base, align, depth); /* server challenge */
DBG_RW_IVAL("status", depth, base, io, q, r_s->status); q += 4;
return q;
}
/* LSA_USER_INFO */
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_user_info(BOOL io, LSA_USER_INFO *usr, char *q, char *base, int align, int depth)
{
int i;
if (usr == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_user_info\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("ptr_user_info ", depth, base, io, q, usr->ptr_user_info); q += 4;
if (usr->ptr_user_info != 0)
{
q = smb_io_time(io, &(usr->logon_time) , q, base, align, depth); /* logon time */
q = smb_io_time(io, &(usr->logoff_time) , q, base, align, depth); /* logoff time */
q = smb_io_time(io, &(usr->kickoff_time) , q, base, align, depth); /* kickoff time */
q = smb_io_time(io, &(usr->pass_last_set_time) , q, base, align, depth); /* password last set time */
q = smb_io_time(io, &(usr->pass_can_change_time) , q, base, align, depth); /* password can change time */
q = smb_io_time(io, &(usr->pass_must_change_time), q, base, align, depth); /* password must change time */
q = smb_io_unihdr(io, &(usr->hdr_user_name) , q, base, align, depth); /* username unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_full_name) , q, base, align, depth); /* user's full name unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_logon_script), q, base, align, depth); /* logon script unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_profile_path), q, base, align, depth); /* profile path unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_home_dir) , q, base, align, depth); /* home directory unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_dir_drive) , q, base, align, depth); /* home directory drive unicode string header */
DBG_RW_SVAL("logon_count ", depth, base, io, q, usr->logon_count ); q += 2; /* logon count */
DBG_RW_SVAL("bad_pw_count ", depth, base, io, q, usr->bad_pw_count); q += 2; /* bad password count */
DBG_RW_IVAL("user_id ", depth, base, io, q, usr->user_id ); q += 4; /* User ID */
DBG_RW_IVAL("group_id ", depth, base, io, q, usr->group_id ); q += 4; /* Group ID */
DBG_RW_IVAL("num_groups ", depth, base, io, q, usr->num_groups ); q += 4; /* num groups */
DBG_RW_IVAL("buffer_groups ", depth, base, io, q, usr->buffer_groups); q += 4; /* undocumented buffer pointer to groups. */
DBG_RW_IVAL("user_flgs ", depth, base, io, q, usr->user_flgs ); q += 4; /* user flags */
DBG_RW_PCVAL(False, "user_sess_key", depth, base, io, q, usr->user_sess_key, 16); q += 16; /* unused user session key */
q = smb_io_unihdr(io, &(usr->hdr_logon_srv), q, base, align, depth); /* logon server unicode string header */
q = smb_io_unihdr(io, &(usr->hdr_logon_dom), q, base, align, depth); /* logon domain unicode string header */
DBG_RW_IVAL("buffer_dom_id ", depth, base, io, q, usr->buffer_dom_id); q += 4; /* undocumented logon domain id pointer */
DBG_RW_PCVAL(False, "padding ", depth, base, io, q, usr->padding, 40); q += 40; /* unused padding bytes? */
DBG_RW_IVAL("num_other_sids", depth, base, io, q, usr->num_other_sids); q += 4; /* 0 - num_sids */
DBG_RW_IVAL("buffer_other_sids", depth, base, io, q, usr->buffer_other_sids); q += 4; /* NULL - undocumented pointer to SIDs. */
q = smb_io_unistr2(io, &(usr->uni_user_name) , q, base, align, depth); /* username unicode string */
q = smb_io_unistr2(io, &(usr->uni_full_name) , q, base, align, depth); /* user's full name unicode string */
q = smb_io_unistr2(io, &(usr->uni_logon_script), q, base, align, depth); /* logon script unicode string */
q = smb_io_unistr2(io, &(usr->uni_profile_path), q, base, align, depth); /* profile path unicode string */
q = smb_io_unistr2(io, &(usr->uni_home_dir) , q, base, align, depth); /* home directory unicode string */
q = smb_io_unistr2(io, &(usr->uni_dir_drive) , q, base, align, depth); /* home directory drive unicode string */
DBG_RW_IVAL("num_groups2 ", depth, base, io, q, usr->num_groups2); q += 4; /* num groups */
for (i = 0; i < usr->num_groups2; i++)
{
q = smb_io_gid(io, &(usr->gids[i]), q, base, align, depth); /* group info */
}
q = smb_io_unistr2(io, &( usr->uni_logon_srv), q, base, align, depth); /* logon server unicode string */
q = smb_io_unistr2(io, &( usr->uni_logon_dom), q, base, align, depth); /* logon domain unicode string */
q = smb_io_dom_sid(io, &(usr->dom_sid), q, base, align, depth); /* domain SID */
for (i = 0; i < usr->num_other_sids; i++)
{
q = smb_io_dom_sid(io, &(usr->other_sids[i]), q, base, align, depth); /* other domain SIDs */
}
}
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_sam_logon(BOOL io, LSA_Q_SAM_LOGON *q_l, char *q, char *base, int align, int depth)
{
if (q_l == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_sam_logon\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_sam_info(io, &(q_l->sam_id), q, base, align, depth); /* domain SID */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_sam_logon(BOOL io, LSA_R_SAM_LOGON *r_l, char *q, char *base, int align, int depth)
{
if (r_l == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_sam_logon\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("buffer_creds", depth, base, io, q, r_l->buffer_creds); q += 4; /* undocumented buffer pointer */
q = smb_io_cred(io, &(r_l->srv_creds), q, base, align, depth); /* server credentials. server time stamp appears to be ignored. */
DBG_RW_SVAL("switch_value", depth, base, io, q, r_l->switch_value); q += 2; /* 1 - Authoritative response; 0 - Non-Auth? */
q = align_offset(q, base, align);
q = lsa_io_user_info(io, r_l->user, q, base, align, depth);
DBG_RW_IVAL("auth_resp ", depth, base, io, q, r_l->auth_resp); q += 4; /* 1 - Authoritative response; 0 - Non-Auth? */
DBG_RW_IVAL("status ", depth, base, io, q, r_l->status); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_q_sam_logoff(BOOL io, LSA_Q_SAM_LOGOFF *q_l, char *q, char *base, int align, int depth)
{
if (q_l == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_q_sam_logoff\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_sam_info(io, &(q_l->sam_id), q, base, align, depth); /* domain SID */
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_r_sam_logoff(BOOL io, LSA_R_SAM_LOGOFF *r_l, char *q, char *base, int align, int depth)
{
if (r_l == NULL) return NULL;
DEBUG(5,("%s%04x lsa_io_r_sam_logoff\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("buffer_creds", depth, base, io, q, r_l->buffer_creds); q += 4; /* undocumented buffer pointer */
q = smb_io_cred(io, &(r_l->srv_creds), q, base, align, depth); /* server credentials. server time stamp appears to be ignored. */
DBG_RW_IVAL("status ", depth, base, io, q, r_l->status); q += 4;
return q;
}
#if 0
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_(BOOL io, *, char *q, char *base, int align, int depth)
{
if (== NULL) return NULL;
q = align_offset(q, base, align);
DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
return q;
}
#endif

View File

@ -1,380 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
NT Domain Authentication SMB / MSRPC client
Copyright (C) Andrew Tridgell 1994-1997
Copyright (C) Luke Kenneth Casson Leighton 1996-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef SYSLOG
#undef SYSLOG
#endif
#include "includes.h"
extern int DEBUGLEVEL;
extern pstring username;
extern pstring workgroup;
#define CLIENT_TIMEOUT (30*1000)
#ifdef NTDOMAIN
/****************************************************************************
do a LSA Open Policy
****************************************************************************/
BOOL do_lsa_open_policy(uint16 fnum, uint32 call_id,
char *server_name, LSA_POL_HND *hnd)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_OPEN_POL q_o;
BOOL valid_pol = False;
if (hnd == NULL) return False;
/* create and send a MSRPC command with api LSA_OPENPOLICY */
DEBUG(4,("LSA Open Policy\n"));
/* store the parameters */
make_q_open_pol(&q_o, server_name, 0, 0, 0x1);
/* turn parameters into data stream */
p = lsa_io_q_open_pol(False, &q_o, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR with no data */
create_rpc_request(call_id, LSA_OPENPOLICY, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt, &rdrcnt,
NULL, data, setup,
&rparam, &rdata))
{
LSA_R_OPEN_POL r_o;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_open_policy: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_open_pol(True, &r_o, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_open_policy: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_o.status != 0)
{
/* report error code */
DEBUG(0,("LSA_OPENPOLICY: nt_status error %lx\n", r_o.status));
p = NULL;
}
if (p)
{
/* ok, at last: we're happy. return the policy handle */
memcpy(hnd, r_o.pol.data, sizeof(hnd->data));
valid_pol = True;
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_pol;
}
/****************************************************************************
do a LSA Query Info Policy
****************************************************************************/
BOOL do_lsa_query_info_pol(uint16 fnum, uint32 call_id,
LSA_POL_HND *hnd, uint16 info_class,
fstring domain_name, pstring domain_sid)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_QUERY_INFO q_q;
BOOL valid_response = False;
if (hnd == NULL || domain_name == NULL || domain_sid == NULL) return False;
/* create and send a MSRPC command with api LSA_QUERYINFOPOLICY */
DEBUG(4,("LSA Query Info Policy\n"));
/* store the parameters */
make_q_query(&q_q, hnd, info_class);
/* turn parameters into data stream */
p = lsa_io_q_query(False, &q_q, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR with no data */
create_rpc_request(call_id, LSA_QUERYINFOPOLICY, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt, &rdrcnt,
NULL, data, setup,
&rparam, &rdata))
{
LSA_R_QUERY_INFO r_q;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_query_info: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_query(True, &r_q, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_query_info: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_q.status != 0)
{
/* report error code */
DEBUG(0,("LSA_QUERYINFOPOLICY: nt_status error %lx\n", r_q.status));
p = NULL;
}
if (p && r_q.info_class != q_q.info_class)
{
/* report different info classes */
DEBUG(0,("LSA_QUERYINFOPOLICY: error info_class (q,r) differ - (%x,%x)\n",
q_q.info_class, r_q.info_class));
p = NULL;
}
if (p)
{
/* ok, at last: we're happy. */
switch (r_q.info_class)
{
case 3:
{
char *dom_name = unistrn2(r_q.dom.id3.uni_domain_name.buffer,
r_q.dom.id3.uni_domain_name.uni_str_len);
char *dom_sid = dom_sid_to_string(&(r_q.dom.id3.dom_sid));
fstrcpy(domain_name, dom_name);
pstrcpy(domain_sid , dom_sid);
valid_response = True;
break;
}
case 5:
{
char *dom_name = unistrn2(r_q.dom.id5.uni_domain_name.buffer,
r_q.dom.id5.uni_domain_name.uni_str_len);
char *dom_sid = dom_sid_to_string(&(r_q.dom.id5.dom_sid));
fstrcpy(domain_name, dom_name);
pstrcpy(domain_sid , dom_sid);
valid_response = True;
break;
}
default:
{
DEBUG(3,("LSA_QUERYINFOPOLICY: unknown info class\n"));
domain_name[0] = 0;
domain_sid [0] = 0;
break;
}
}
DEBUG(3,("LSA_QUERYINFOPOLICY (level %x): domain:%s domain sid:%s\n",
r_q.info_class, domain_name, domain_sid));
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_response;
}
/****************************************************************************
do a LSA Close
****************************************************************************/
BOOL do_lsa_close(uint16 fnum, uint32 call_id,
LSA_POL_HND *hnd)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_CLOSE q_c;
BOOL valid_close = False;
if (hnd == NULL) return False;
/* create and send a MSRPC command with api LSA_OPENPOLICY */
DEBUG(4,("LSA Close\n"));
/* store the parameters */
make_q_close(&q_c, hnd);
/* turn parameters into data stream */
p = lsa_io_q_close(False, &q_c, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR with no data */
create_rpc_request(call_id, LSA_CLOSE, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt, &rdrcnt,
NULL, data, setup,
&rparam, &rdata))
{
LSA_R_CLOSE r_c;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_close: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_close(True, &r_c, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_close: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_c.status != 0)
{
/* report error code */
DEBUG(0,("LSA_OPENPOLICY: nt_status error %lx\n", r_c.status));
p = NULL;
}
if (p)
{
/* check that the returned policy handle is all zeros */
int i;
valid_close = True;
for (i = 0; i < sizeof(r_c.pol.data); i++)
{
if (r_c.pol.data[i] != 0)
{
valid_close = False;
break;
}
}
if (!valid_close)
{
DEBUG(0,("LSA_CLOSE: non-zero handle returned\n"));
}
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_close;
}
#endif /* NTDOMAIN */

View File

@ -1,481 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
NT Domain Authentication SMB / MSRPC client
Copyright (C) Andrew Tridgell 1994-1997
Copyright (C) Luke Kenneth Casson Leighton 1996-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef SYSLOG
#undef SYSLOG
#endif
#include "includes.h"
extern int DEBUGLEVEL;
extern pstring username;
extern pstring workgroup;
#define CLIENT_TIMEOUT (30*1000)
#ifdef NTDOMAIN
/****************************************************************************
do a LSA Request Challenge
****************************************************************************/
BOOL do_lsa_req_chal(uint16 fnum, uint32 call_id,
char *desthost, char *myhostname,
DOM_CHAL *clnt_chal, DOM_CHAL *srv_chal)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_REQ_CHAL q_c;
BOOL valid_chal = False;
if (srv_chal == NULL || clnt_chal == NULL) return False;
/* create and send a MSRPC command with api LSA_REQCHAL */
DEBUG(4,("LSA Request Challenge from %s to %s: %lx %lx\n",
desthost, myhostname, clnt_chal->data[0], clnt_chal->data[1]));
/* store the parameters */
make_q_req_chal(&q_c, desthost, myhostname, clnt_chal);
/* turn parameters into data stream */
p = lsa_io_q_req_chal(False, &q_c, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR _after_ the main data: length is now known */
create_rpc_request(call_id, LSA_REQCHAL, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt,&rdrcnt,
NULL, data, setup,
&rparam,&rdata))
{
LSA_R_REQ_CHAL r_c;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_req_chal: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_req_chal(True, &r_c, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_req_chal: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_c.status != 0)
{
/* report error code */
DEBUG(0,("LSA_REQ_CHAL: nt_status error %lx\n", r_c.status));
p = NULL;
}
if (p)
{
/* ok, at last: we're happy. return the challenge */
memcpy(srv_chal, r_c.srv_chal.data, sizeof(srv_chal->data));
valid_chal = True;
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_chal;
}
/****************************************************************************
do a LSA Authenticate 2
****************************************************************************/
BOOL do_lsa_auth2(uint16 fnum, uint32 call_id,
char *logon_srv, char *acct_name, uint16 sec_chan, char *comp_name,
DOM_CHAL *clnt_chal, uint32 neg_flags, DOM_CHAL *srv_chal)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_AUTH_2 q_a;
BOOL valid_chal = False;
if (srv_chal == NULL || clnt_chal == NULL) return False;
/* create and send a MSRPC command with api LSA_AUTH2 */
DEBUG(4,("LSA Authenticate 2: srv:%s acct:%s sc:%x mc: %s chal %lx %lx neg: %lx\n",
logon_srv, acct_name, sec_chan, comp_name,
clnt_chal->data[0], clnt_chal->data[1], neg_flags));
/* store the parameters */
make_q_auth_2(&q_a, logon_srv, acct_name, sec_chan, comp_name,
clnt_chal, neg_flags);
/* turn parameters into data stream */
p = lsa_io_q_auth_2(False, &q_a, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR _after_ the main data: length is now known */
create_rpc_request(call_id, LSA_AUTH2, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt,&rdrcnt,
NULL, data, setup,
&rparam,&rdata))
{
LSA_R_AUTH_2 r_a;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_auth2: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_auth_2(True, &r_a, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_auth2: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_a.status != 0)
{
/* report error code */
DEBUG(0,("LSA_AUTH2: nt_status error %lx\n", r_a.status));
p = NULL;
}
if (p && r_a.srv_flgs.neg_flags != q_a.clnt_flgs.neg_flags)
{
/* report different neg_flags */
DEBUG(0,("LSA_AUTH2: error neg_flags (q,r) differ - (%lx,%lx)\n",
q_a.clnt_flgs.neg_flags, r_a.srv_flgs.neg_flags));
p = NULL;
}
if (p)
{
/* ok, at last: we're happy. return the challenge */
memcpy(srv_chal, r_a.srv_chal.data, sizeof(srv_chal->data));
valid_chal = True;
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_chal;
}
/***************************************************************************
do a LSA SAM Logon
****************************************************************************/
BOOL do_lsa_sam_logon(uint16 fnum, uint32 call_id,
uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
char *logon_srv, char *comp_name,
DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
LSA_USER_INFO *user_info,
DOM_CRED *srv_cred)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_SAM_LOGON q_s;
BOOL valid_cred = False;
if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL || user_info == NULL) return False;
/* create and send a MSRPC command with api LSA_SAMLOGON */
DEBUG(4,("LSA SAM Logon: srv:%s mc:%s clnt %lx %lx %lx rtn: %lx %lx %lx ll: %d\n",
logon_srv, comp_name,
clnt_cred->challenge.data[0], clnt_cred->challenge.data[1], clnt_cred->timestamp.time,
rtn_cred ->challenge.data[0], rtn_cred ->challenge.data[1], rtn_cred ->timestamp.time,
logon_level));
/* store the parameters */
make_sam_info(&(q_s.sam_id), logon_srv, comp_name,
clnt_cred, rtn_cred, logon_level, switch_value, id1);
/* turn parameters into data stream */
p = lsa_io_q_sam_logon(False, &q_s, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR _after_ the main data: length is now known */
create_rpc_request(call_id, LSA_SAMLOGON, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt,&rdrcnt,
NULL, data, setup,
&rparam,&rdata))
{
LSA_R_SAM_LOGON r_s;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
r_s.user = user_info;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_sam_logon: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_sam_logon(True, &r_s, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_sam_logon: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_s.status != 0)
{
/* report error code */
DEBUG(0,("LSA_SAMLOGON: nt_status error %lx\n", r_s.status));
p = NULL;
}
if (p && r_s.switch_value != 3)
{
/* report different switch_value */
DEBUG(0,("LSA_SAMLOGON: switch_value of 3 expected %x\n",
r_s.switch_value));
p = NULL;
}
if (p)
{
if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds)))
{
DEBUG(5, ("do_lsa_sam_logon: server credential check OK\n"));
/* ok, at last: we're happy. return the challenge */
memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds));
valid_cred = True;
}
else
{
DEBUG(5, ("do_lsa_sam_logon: server credential check failed\n"));
}
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_cred;
}
/***************************************************************************
do a LSA SAM Logoff
****************************************************************************/
BOOL do_lsa_sam_logoff(uint16 fnum, uint32 call_id,
uint32 sess_key[2], DOM_CRED *sto_clnt_cred,
char *logon_srv, char *comp_name,
DOM_CRED *clnt_cred, DOM_CRED *rtn_cred,
uint16 logon_level, uint16 switch_value, DOM_ID_INFO_1 *id1,
DOM_CRED *srv_cred)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
LSA_Q_SAM_LOGOFF q_s;
BOOL valid_cred = False;
if (srv_cred == NULL || clnt_cred == NULL || rtn_cred == NULL) return False;
/* create and send a MSRPC command with api LSA_SAMLOGON */
DEBUG(4,("LSA SAM Logoff: srv:%s mc:%s clnt %lx %lx %lx rtn: %lx %lx %lx ll: %d\n",
logon_srv, comp_name,
clnt_cred->challenge.data[0], clnt_cred->challenge.data[1], clnt_cred->timestamp.time,
rtn_cred ->challenge.data[0], rtn_cred ->challenge.data[1], rtn_cred ->timestamp.time,
logon_level));
/* store the parameters */
make_sam_info(&(q_s.sam_id), logon_srv, comp_name,
clnt_cred, rtn_cred, logon_level, switch_value, id1);
/* turn parameters into data stream */
p = lsa_io_q_sam_logoff(False, &q_s, data + 0x18, data, 4, 0);
/* create the request RPC_HDR_RR _after_ the main data: length is now known */
create_rpc_request(call_id, LSA_SAMLOGOFF, data, PTR_DIFF(p, data));
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, PTR_DIFF(p, data), 2, 1024,
BUFFER_SIZE,
&rprcnt,&rdrcnt,
NULL, data, setup,
&rparam,&rdata))
{
LSA_R_SAM_LOGOFF r_s;
RPC_HDR_RR hdr;
int hdr_len;
int pkt_len;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr_rr (True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("do_lsa_sam_logoff: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p) p = lsa_io_r_sam_logoff(True, &r_s, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("do_lsa_sam_logoff: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
if (p && r_s.status != 0)
{
/* report error code */
DEBUG(0,("LSA_SAMLOGOFF: nt_status error %lx\n", r_s.status));
p = NULL;
}
if (p)
{
if (clnt_deal_with_creds(sess_key, sto_clnt_cred, &(r_s.srv_creds)))
{
DEBUG(5, ("do_lsa_sam_logoff: server credential check OK\n"));
/* ok, at last: we're happy. return the challenge */
memcpy(srv_cred, &(r_s.srv_creds), sizeof(r_s.srv_creds));
valid_cred = True;
}
else
{
DEBUG(5, ("do_lsa_sam_logoff: server credential check failed\n"));
}
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_cred;
}
#endif /* NTDOMAIN */

View File

@ -1,257 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
NT Domain Authentication SMB / MSRPC client
Copyright (C) Andrew Tridgell 1994-1997
Copyright (C) Luke Kenneth Casson Leighton 1996-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef SYSLOG
#undef SYSLOG
#endif
#include "includes.h"
extern int DEBUGLEVEL;
extern pstring username;
extern pstring workgroup;
#define CLIENT_TIMEOUT (30*1000)
#ifdef NTDOMAIN
/****************************************************************************
open an rpc pipe (\NETLOGON or \srvsvc for example)
****************************************************************************/
uint16 open_rpc_pipe(char *inbuf, char *outbuf, char *rname, int Client, int cnum)
{
int fnum;
char *p;
DEBUG(5,("open_rpc_pipe: %s\n", rname));
bzero(outbuf,smb_size);
set_message(outbuf,15,1 + strlen(rname),True);
CVAL(outbuf,smb_com) = SMBopenX;
SSVAL(outbuf,smb_tid, cnum);
cli_setup_pkt(outbuf);
SSVAL(outbuf,smb_vwv0,0xFF);
SSVAL(outbuf,smb_vwv2,1);
SSVAL(outbuf,smb_vwv3,(DENY_NONE<<4));
SSVAL(outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
SSVAL(outbuf,smb_vwv8,1);
p = smb_buf(outbuf);
strcpy(p,rname);
p = skip_string(p,1);
send_smb(Client,outbuf);
receive_smb(Client,inbuf,CLIENT_TIMEOUT);
if (CVAL(inbuf,smb_rcls) != 0)
{
if (CVAL(inbuf,smb_rcls) == ERRSRV &&
SVAL(inbuf,smb_err) == ERRnoresource &&
cli_reopen_connection(inbuf,outbuf))
{
return open_rpc_pipe(inbuf, outbuf, rname, Client, cnum);
}
DEBUG(0,("opening remote pipe %s - error %s\n", rname, smb_errstr(inbuf)));
return 0xffff;
}
fnum = SVAL(inbuf, smb_vwv2);
DEBUG(5,("opening pipe: fnum %d\n", fnum));
return fnum;
}
struct
{
char *client;
char *server;
} pipe_names [] =
{
{ PIPE_LSARPC , PIPE_LSASS },
{ PIPE_NETLOGON, PIPE_NETLOGON },
{ NULL , NULL }
};
/****************************************************************************
do an rpc bind
****************************************************************************/
BOOL bind_rpc_pipe(char *pipe_name, uint16 fnum, uint32 call_id,
RPC_IFACE *abstract, RPC_IFACE *transfer)
{
char *rparam = NULL;
char *rdata = NULL;
char *p;
int rdrcnt,rprcnt;
int data_len;
pstring data; /* only 1024 bytes */
uint16 setup[2]; /* only need 2 uint16 setup parameters */
RPC_HDR hdr;
RPC_HDR_RB hdr_rb;
BOOL valid_ack = False;
if (pipe_name == NULL || abstract == NULL || transfer == NULL) return False;
DEBUG(5,("Bind RPC Pipe[%x]: %s\n", fnum, pipe_name));
/* create the request RPC_HDR_RB */
make_rpc_hdr_rb(&hdr_rb,
0x1630, 0x1630, 0x0,
0x1, 0x1, 0x1,
abstract, transfer);
/* stream the bind request data */
p = smb_io_rpc_hdr_rb(False, &hdr_rb, data + 0x10, data, 4, 0);
data_len = PTR_DIFF(p, data);
/* create the request RPC_HDR */
make_rpc_hdr(&hdr, RPC_BIND, 0x0, call_id, PTR_DIFF(p, data + 0x10));
/* stream the header into data */
p = smb_io_rpc_hdr(False, &hdr, data, data, 4, 0);
/* create setup parameters. */
setup[0] = 0x0026; /* 0x26 indicates "transact named pipe" */
setup[1] = fnum; /* file handle, from the SMBcreateX pipe, earlier */
/* send the data on \PIPE\ */
if (cli_call_api("\\PIPE\\", 0, data_len, 2, 1024,
BUFFER_SIZE,
&rprcnt, &rdrcnt,
NULL, data, setup,
&rparam, &rdata))
{
RPC_HDR_BA hdr_ba;
int hdr_len;
int pkt_len;
int i = 0;
DEBUG(5, ("cli_call_api: return OK\n"));
p = rdata;
if (p) p = smb_io_rpc_hdr(True, &hdr, p, rdata, 4, 0);
if (p) p = align_offset(p, rdata, 4); /* oh, what a surprise */
hdr_len = PTR_DIFF(p, rdata);
if (p) p = smb_io_rpc_hdr_ba(True, &hdr_ba, p, rdata, 4, 0);
pkt_len = PTR_DIFF(p, rdata);
#if 0
if (p && hdr_len != hdr.hdr.frag_len - hdr.alloc_hint)
{
/* header length not same as calculated header length */
DEBUG(2,("bind_rpc_pipe: hdr_len %x != frag_len-alloc_hint %x\n",
hdr_len, hdr.hdr.frag_len - hdr.alloc_hint));
p = NULL;
}
if (p && pkt_len != hdr.hdr.frag_len)
{
/* packet data size not same as reported fragment length */
DEBUG(2,("bind_rpc_pipe: pkt_len %x != frag_len \n",
pkt_len, hdr.hdr.frag_len));
p = NULL;
}
#endif
while (p && (pipe_names[i].server != NULL))
{
DEBUG(6,("bind_rpc_pipe: searching pipe name: client:%s server:%s\n",
pipe_names[i].client, pipe_names[i].server));
if ((strcmp(pipe_name , pipe_names[i].client) == 0))
{
if (strcmp(hdr_ba.addr.str, pipe_names[i].server) == 0)
{
DEBUG(5,("bind_rpc_pipe: server pipe_name found: %s\n",
pipe_names[i].server));
break;
}
else
{
DEBUG(2,("bind_rpc_pipe: pipe_name %s != expected pipe %s\n",
pipe_names[i].server, hdr_ba.addr.str));
p = NULL;
}
}
else
{
i++;
}
}
if (p && pipe_names[i].server == NULL)
{
DEBUG(2,("bind_rpc_pipe: pipe name %s unsupported\n", hdr_ba.addr.str));
p = NULL;
}
if (p)
{
/* check the transfer syntax */
valid_ack = (hdr_ba.transfer.version == transfer->version) &&
(memcmp(hdr_ba.transfer.data, transfer->data,
sizeof(transfer->version)) ==0);
if (!valid_ack)
{
DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
p = NULL;
}
}
if (p)
{
/* check the results */
valid_ack = (hdr_ba.res.num_results == 0x1) &&
(hdr_ba.res.result == 0);
if (!valid_ack)
{
DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
hdr_ba.res.num_results,
hdr_ba.res.reason));
p = NULL;
}
else
{
DEBUG(5,("bind_rpc_pipe: accepted!\n"));
}
}
}
if (rparam) free(rparam);
if (rdata) free(rdata);
return valid_ack;
}
#endif /* NTDOMAIN */

View File

@ -1,660 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Pipe SMB reply routines
Copyright (C) Andrew Tridgell 1992-1997,
Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
Copyright (C) Paul Ashton 1997.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This file handles reply_ calls on named pipes that the server
makes to handle specific protocols
*/
#include "includes.h"
#include "trans2.h"
#include "nterr.h"
extern int DEBUGLEVEL;
extern BOOL sam_logon_in_ssb;
extern pstring samlogon_user;
#ifdef NTDOMAIN
static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c,
DOM_CHAL *srv_chal, int status)
{
DEBUG(6,("make_lsa_r_req_chal: %d\n", __LINE__));
memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
r_c->status = status;
}
static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base,
DOM_CHAL *srv_chal, uint32 srv_time)
{
LSA_R_REQ_CHAL r_c;
DEBUG(6,("lsa_reply_req_chal: %d\n", __LINE__));
/* set up the LSA REQUEST CHALLENGE response */
make_lsa_r_req_chal(&r_c, srv_chal, srv_time);
/* store the response in the SMB stream */
q = lsa_io_r_req_chal(False, &r_c, q, base, 4, 0);
DEBUG(6,("lsa_reply_req_chal: %d\n", __LINE__));
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a,
DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
{
memcpy( r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
memcpy(&(r_a->srv_flgs) , flgs , sizeof(r_a->srv_flgs));
r_a->status = status;
}
static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base,
DOM_CHAL *resp_cred, int status)
{
LSA_R_AUTH_2 r_a;
/* set up the LSA AUTH 2 response */
make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
/* store the response in the SMB stream */
q = lsa_io_r_auth_2(False, &r_a, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_s,
DOM_CRED *srv_cred, int status)
{
DEBUG(5,("make_lsa_r_srv_pwset: %d\n", __LINE__));
memcpy(&(r_s->srv_cred), srv_cred, sizeof(r_s->srv_cred));
r_s->status = status;
DEBUG(5,("make_lsa_r_srv_pwset: %d\n", __LINE__));
}
static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base,
DOM_CRED *srv_cred, int status)
{
LSA_R_SRV_PWSET r_s;
DEBUG(5,("lsa_srv_pwset: %d\n", __LINE__));
/* set up the LSA Server Password Set response */
make_lsa_r_srv_pwset(&r_s, srv_cred, status);
/* store the response in the SMB stream */
q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4, 0);
DEBUG(5,("lsa_srv_pwset: %d\n", __LINE__));
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
static void make_lsa_user_info(LSA_USER_INFO *usr,
NTTIME *logon_time,
NTTIME *logoff_time,
NTTIME *kickoff_time,
NTTIME *pass_last_set_time,
NTTIME *pass_can_change_time,
NTTIME *pass_must_change_time,
char *user_name,
char *full_name,
char *logon_script,
char *profile_path,
char *home_dir,
char *dir_drive,
uint16 logon_count,
uint16 bad_pw_count,
uint32 user_id,
uint32 group_id,
uint32 num_groups,
DOM_GID *gids,
uint32 user_flgs,
char sess_key[16],
char *logon_srv,
char *logon_dom,
char *dom_sid,
char *other_sids) /* space-delimited set of SIDs */
{
/* only cope with one "other" sid, right now. */
/* need to count the number of space-delimited sids */
int i;
int num_other_sids = 0;
int len_user_name = strlen(user_name );
int len_full_name = strlen(full_name );
int len_logon_script = strlen(logon_script);
int len_profile_path = strlen(profile_path);
int len_home_dir = strlen(home_dir );
int len_dir_drive = strlen(dir_drive );
int len_logon_srv = strlen(logon_srv);
int len_logon_dom = strlen(logon_dom);
usr->ptr_user_info = 1; /* yes, we're bothering to put USER_INFO data here */
usr->logon_time = *logon_time;
usr->logoff_time = *logoff_time;
usr->kickoff_time = *kickoff_time;
usr->pass_last_set_time = *pass_last_set_time;
usr->pass_can_change_time = *pass_can_change_time;
usr->pass_must_change_time = *pass_must_change_time;
make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , 4);
make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , 4);
make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , 4);
make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , 4);
usr->logon_count = logon_count;
usr->bad_pw_count = bad_pw_count;
usr->user_id = user_id;
usr->group_id = group_id;
usr->num_groups = num_groups;
usr->buffer_groups = 1; /* indicates fill in groups, below, even if there are none */
usr->user_flgs = user_flgs;
if (sess_key != NULL)
{
memcpy(usr->user_sess_key, sess_key, sizeof(usr->user_sess_key));
}
else
{
bzero(usr->user_sess_key, sizeof(usr->user_sess_key));
}
make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
bzero(usr->padding, sizeof(usr->padding));
num_other_sids = make_dom_sids(other_sids, usr->other_sids, LSA_MAX_SIDS);
usr->num_other_sids = num_other_sids;
usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0;
make_unistr2(&(usr->uni_user_name ), user_name , len_user_name );
make_unistr2(&(usr->uni_full_name ), full_name , len_full_name );
make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script);
make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path);
make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir );
make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive );
usr->num_groups2 = num_groups;
for (i = 0; i < num_groups; i++)
{
usr->gids[i] = gids[i];
}
make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv);
make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom);
make_dom_sid(&(usr->dom_sid), dom_sid);
/* "other" sids are set up above */
}
static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base,
DOM_CRED *srv_cred, LSA_USER_INFO *user_info)
{
LSA_R_SAM_LOGON r_s;
/* XXXX maybe we want to say 'no', reject the client's credentials */
r_s.buffer_creds = 1; /* yes, we have valid server credentials */
memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
/* store the user information, if there is any. */
r_s.user = user_info;
if (user_info != NULL && user_info->ptr_user_info != 0)
{
r_s.switch_value = 3; /* indicates type of validation user info */
r_s.status = 0;
}
else
{
r_s.switch_value = 0; /* don't know what this value is supposed to be */
r_s.status = 0xC000000|NT_STATUS_NO_SUCH_USER;
}
r_s.auth_resp = 1; /* authoritative response */
/* store the response in the SMB stream */
q = lsa_io_r_sam_logon(False, &r_s, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base,
DOM_CRED *srv_cred,
uint32 status)
{
LSA_R_SAM_LOGOFF r_s;
/* XXXX maybe we want to say 'no', reject the client's credentials */
r_s.buffer_creds = 1; /* yes, we have valid server credentials */
memcpy(&(r_s.srv_creds), srv_cred, sizeof(r_s.srv_creds));
r_s.status = status;
/* store the response in the SMB stream */
q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/****************************************************************************
gets a machine password entry
****************************************************************************/
BOOL get_md4pw(char *md4pw, char *mach_acct)
{
struct smb_passwd *smb_pass;
become_root(True);
smb_pass = get_smbpwnam(mach_acct);
unbecome_root(True);
if (smb_pass != NULL)
{
memcpy(md4pw, smb_pass->smb_nt_passwd, 16);
dump_data(5, md4pw, 16);
return True;
}
else
{
/* No such machine account. Should error out here, but we'll
print and carry on */
DEBUG(1,("No account in domain for %s\n", mach_acct));
return False;
}
}
static void api_lsa_req_chal( int cnum, uint16 vuid,
user_struct *vuser,
char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_REQ_CHAL q_r;
fstring mach_acct;
/* grab the challenge... */
lsa_io_q_req_chal(True, &q_r, data + 0x18, data, 4, 0);
fstrcpy(mach_acct, unistrn2(q_r.uni_logon_clnt.buffer,
q_r.uni_logon_clnt.uni_str_len));
strcat(mach_acct, "$");
DEBUG(6,("q_r.clnt_chal.data: %lx %lx\n",
q_r.clnt_chal.data[0], q_r.clnt_chal.data[1]));
if (get_md4pw(vuser->dc.md4pw, mach_acct))
{
/* copy the client credentials */
memcpy(vuser->dc.clnt_chal.data , q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
memcpy(vuser->dc.clnt_cred.challenge.data, q_r.clnt_chal.data, sizeof(q_r.clnt_chal.data));
/* create a server challenge for the client */
/* PAXX: set these to random values. */
/* lkcl: paul, you mentioned that it doesn't really matter much */
vuser->dc.srv_chal.data[0] = 0x11111111;
vuser->dc.srv_chal.data[1] = 0x11111111;
vuser->dc.srv_cred.challenge.data[0] = vuser->dc.srv_chal.data[0];
vuser->dc.srv_cred.challenge.data[1] = vuser->dc.srv_chal.data[1];
/* from client / server challenges and md4 password, generate sess key */
cred_session_key(&(vuser->dc.clnt_chal), &(vuser->dc.srv_chal),
vuser->dc.md4pw, vuser->dc.sess_key);
}
/* construct reply. return status is always 0x0 */
*rdata_len = lsa_reply_req_chal(&q_r, *rdata + 0x18, *rdata,
&(vuser->dc.srv_chal), 0);
}
static void api_lsa_auth_2( user_struct *vuser,
char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_AUTH_2 q_a;
DOM_CHAL srv_cred;
UTIME srv_time;
srv_time.time = 0;
/* grab the challenge... */
lsa_io_q_auth_2(True, &q_a, data + 0x18, data, 4, 0);
/* check that the client credentials are valid */
cred_assert(&(q_a.clnt_chal), vuser->dc.sess_key,
&(vuser->dc.clnt_cred.challenge), srv_time);
/* create server challenge for inclusion in the reply */
cred_create(vuser->dc.sess_key, &(vuser->dc.srv_cred.challenge), srv_time, &srv_cred);
/* copy the received client credentials for use next time */
memcpy(vuser->dc.clnt_cred.challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
memcpy(vuser->dc.srv_cred .challenge.data, &(q_a.clnt_chal.data), sizeof(q_a.clnt_chal.data));
/* construct reply. */
*rdata_len = lsa_reply_auth_2(&q_a, *rdata + 0x18, *rdata,
&srv_cred, 0x0);
}
static void api_lsa_srv_pwset( user_struct *vuser,
char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_SRV_PWSET q_a;
DOM_CRED srv_cred;
/* grab the challenge and encrypted password ... */
lsa_io_q_srv_pwset(True, &q_a, data + 0x18, data, 4, 0);
/* checks and updates credentials. creates reply credentials */
deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
&(q_a.clnt_id.cred), &srv_cred);
memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
DEBUG(5,("api_lsa_srv_pwset: %d\n", __LINE__));
/* construct reply. always indicate failure. nt keeps going... */
*rdata_len = lsa_reply_srv_pwset(&q_a, *rdata + 0x18, *rdata,
&srv_cred,
NT_STATUS_WRONG_PASSWORD|0xC0000000);
}
static void api_lsa_sam_logoff( user_struct *vuser,
char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_SAM_LOGOFF q_l;
DOM_ID_INFO_1 id1;
DOM_CRED srv_cred;
/* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
dynamically allocate it inside lsa_io_q_sam_logon, at some point */
q_l.sam_id.auth.id1 = &id1;
/* grab the challenge... */
lsa_io_q_sam_logoff(True, &q_l, data + 0x18, data, 4, 0);
/* checks and updates credentials. creates reply credentials */
deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
&(q_l.sam_id.client.cred), &srv_cred);
memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
/* construct reply. always indicate success */
*rdata_len = lsa_reply_sam_logoff(&q_l, *rdata + 0x18, *rdata,
&srv_cred,
0x0);
}
static void api_lsa_sam_logon( user_struct *vuser,
char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_SAM_LOGON q_l;
DOM_ID_INFO_1 id1;
LSA_USER_INFO usr_info;
DOM_CRED srv_cred;
/* the DOM_ID_INFO_1 structure is a bit big. plus we might want to
dynamically allocate it inside lsa_io_q_sam_logon, at some point */
q_l.sam_id.auth.id1 = &id1;
lsa_io_q_sam_logon(True, &q_l, data + 0x18, data, 4, 0);
/* checks and updates credentials. creates reply credentials */
deal_with_creds(vuser->dc.sess_key, &(vuser->dc.clnt_cred),
&(q_l.sam_id.client.cred), &srv_cred);
memcpy(&(vuser->dc.srv_cred), &(vuser->dc.clnt_cred), sizeof(vuser->dc.clnt_cred));
usr_info.ptr_user_info = 0;
if (vuser != NULL)
{
DOM_GID gids[LSA_MAX_GROUPS];
int num_gids;
NTTIME dummy_time;
pstring logon_script;
pstring profile_path;
pstring home_dir;
pstring home_drive;
pstring my_name;
pstring my_workgroup;
pstring domain_groups;
pstring dom_sid;
pstring other_sids;
fstring tmp;
extern pstring myname;
uint32 r_uid;
uint32 r_gid;
UNISTR2 *uni_samlogon_user = &(q_l.sam_id.auth.id1->uni_user_name);
dummy_time.low = 0xffffffff;
dummy_time.high = 0x7fffffff;
get_myname(myname, NULL);
pstrcpy(samlogon_user, unistrn2(uni_samlogon_user->buffer,
uni_samlogon_user->uni_str_len));
DEBUG(3,("SAM Logon. Domain:[%s]. User:[%s]\n",
lp_workgroup(), samlogon_user));
/* hack to get standard_sub_basic() to use the sam logon username */
sam_logon_in_ssb = True;
pstrcpy(logon_script, lp_logon_script ());
pstrcpy(profile_path, lp_logon_path ());
pstrcpy(dom_sid , lp_domain_sid ());
pstrcpy(other_sids , lp_domain_other_sids());
pstrcpy(my_workgroup, lp_workgroup ());
pstrcpy(home_drive , lp_logon_drive ());
pstrcpy(home_dir , lp_logon_home ());
/* any additional groups this user is in. e.g power users */
pstrcpy(domain_groups, lp_domain_groups());
/* can only be a user or a guest. cannot be guest _and_ admin */
if (user_in_list(samlogon_user, lp_domain_guest_users()))
{
sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_GUESTS);
strcat(domain_groups, tmp);
DEBUG(3,("domain guest access %s granted\n", tmp));
}
else
{
sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_USERS);
strcat(domain_groups, tmp);
DEBUG(3,("domain user access %s granted\n", tmp));
if (user_in_list(samlogon_user, lp_domain_admin_users()))
{
sprintf(tmp, " %ld/7 ", DOMAIN_GROUP_RID_ADMINS);
strcat(domain_groups, tmp);
DEBUG(3,("domain admin access %s granted\n", tmp));
}
}
num_gids = make_dom_gids(domain_groups, gids);
sam_logon_in_ssb = False;
pstrcpy(my_name , myname );
strupper(my_name);
if (name_to_rid(samlogon_user, &r_uid, &r_gid))
{
make_lsa_user_info(&usr_info,
&dummy_time, /* logon_time */
&dummy_time, /* logoff_time */
&dummy_time, /* kickoff_time */
&dummy_time, /* pass_last_set_time */
&dummy_time, /* pass_can_change_time */
&dummy_time, /* pass_must_change_time */
samlogon_user, /* user_name */
vuser->real_name, /* full_name */
logon_script, /* logon_script */
profile_path, /* profile_path */
home_dir, /* home_dir */
home_drive, /* dir_drive */
0, /* logon_count */
0, /* bad_pw_count */
r_uid, /* RID user_id */
r_gid, /* RID group_id */
num_gids, /* uint32 num_groups */
gids, /* DOM_GID *gids */
0x20, /* uint32 user_flgs */
NULL, /* char sess_key[16] */
my_name , /* char *logon_srv */
my_workgroup, /* char *logon_dom */
dom_sid, /* char *dom_sid */
other_sids); /* char *other_sids */
}
}
*rdata_len = lsa_reply_sam_logon(&q_l, *rdata + 0x18, *rdata,
&srv_cred, &usr_info);
}
BOOL api_netlogrpcTNP(int cnum,int uid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
{
user_struct *vuser;
RPC_HDR_RR hdr;
if (data == NULL)
{
DEBUG(2,("api_netlogrpcTNP: NULL data received\n"));
return False;
}
smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
DEBUG(4,("netlogon TransactNamedPipe op %x\n",hdr.opnum));
if ((vuser = get_valid_user_struct(uid)) == NULL) return False;
DEBUG(3,("Username of UID %d is %s\n", vuser->uid, vuser->name));
switch (hdr.opnum)
{
case LSA_REQCHAL:
{
DEBUG(3,("LSA_REQCHAL\n"));
api_lsa_req_chal(cnum, uid, vuser, param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_AUTH2:
{
DEBUG(3,("LSA_AUTH2\n"));
api_lsa_auth_2(vuser, param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_SRVPWSET:
{
DEBUG(3,("LSA_SRVPWSET\n"));
api_lsa_srv_pwset(vuser, param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_SAMLOGON:
{
DEBUG(3,("LSA_SAMLOGON\n"));
api_lsa_sam_logon(vuser, param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_SAMLOGOFF:
{
DEBUG(3,("LSA_SAMLOGOFF\n"));
api_lsa_sam_logoff(vuser, param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
default:
{
DEBUG(4, ("**** netlogon, unknown code: %lx\n", hdr.opnum));
break;
}
}
return True;
}
#endif /* NTDOMAIN */

View File

@ -1,464 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Pipe SMB reply routines
Copyright (C) Andrew Tridgell 1992-1997,
Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
Copyright (C) Paul Ashton 1997.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This file handles reply_ calls on named pipes that the server
makes to handle specific protocols
*/
#include "includes.h"
#include "trans2.h"
#include "nterr.h"
extern int DEBUGLEVEL;
#ifdef NTDOMAIN
/***************************************************************************
lsa_reply_open_policy
***************************************************************************/
static int lsa_reply_open_policy(char *q, char *base)
{
int i;
LSA_R_OPEN_POL r_o;
/* set up the LSA QUERY INFO response */
bzero(&(r_o.pol.data), POL_HND_SIZE);
for (i = 4; i < POL_HND_SIZE; i++)
{
r_o.pol.data[i] = i;
}
r_o.status = 0x0;
/* store the response in the SMB stream */
q = lsa_io_r_open_pol(False, &r_o, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/***************************************************************************
make_dom_query
***************************************************************************/
static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid)
{
int domlen = strlen(dom_name);
d_q->uni_dom_max_len = domlen * 2;
d_q->uni_dom_str_len = domlen * 2;
d_q->buffer_dom_name = 4; /* domain buffer pointer */
d_q->buffer_dom_sid = 2; /* domain sid pointer */
/* this string is supposed to be character short */
make_unistr2(&(d_q->uni_domain_name), dom_name, domlen);
make_dom_sid(&(d_q->dom_sid), dom_sid);
}
/***************************************************************************
lsa_reply_query_info
***************************************************************************/
static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base,
char *dom_name, char *dom_sid)
{
LSA_R_QUERY_INFO r_q;
/* set up the LSA QUERY INFO response */
r_q.undoc_buffer = 0x22000000; /* bizarre */
r_q.info_class = q_q->info_class;
make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
r_q.status = 0x0;
/* store the response in the SMB stream */
q = lsa_io_r_query(False, &r_q, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/***************************************************************************
make_dom_ref
pretty much hard-coded choice of "other" sids, unfortunately...
***************************************************************************/
static void make_dom_ref(DOM_R_REF *ref,
char *dom_name, char *dom_sid,
char *other_sid1, char *other_sid2, char *other_sid3)
{
int len_dom_name = strlen(dom_name);
int len_other_sid1 = strlen(other_sid1);
int len_other_sid2 = strlen(other_sid2);
int len_other_sid3 = strlen(other_sid3);
ref->undoc_buffer = 1;
ref->num_ref_doms_1 = 4;
ref->buffer_dom_name = 1;
ref->max_entries = 32;
ref->num_ref_doms_2 = 4;
make_uni_hdr2(&(ref->hdr_dom_name ), len_dom_name , len_dom_name , 0);
make_uni_hdr2(&(ref->hdr_ref_dom[0]), len_other_sid1, len_other_sid1, 0);
make_uni_hdr2(&(ref->hdr_ref_dom[1]), len_other_sid2, len_other_sid2, 0);
make_uni_hdr2(&(ref->hdr_ref_dom[2]), len_other_sid3, len_other_sid3, 0);
if (dom_name != NULL)
{
make_unistr(&(ref->uni_dom_name), dom_name);
}
make_dom_sid(&(ref->ref_dom[0]), dom_sid );
make_dom_sid(&(ref->ref_dom[1]), other_sid1);
make_dom_sid(&(ref->ref_dom[2]), other_sid2);
make_dom_sid(&(ref->ref_dom[3]), other_sid3);
}
/***************************************************************************
make_reply_lookup_rids
***************************************************************************/
static void make_reply_lookup_rids(LSA_R_LOOKUP_RIDS *r_l,
int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
char *dom_name, char *dom_sid,
char *other_sid1, char *other_sid2, char *other_sid3)
{
int i;
make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
other_sid1, other_sid2, other_sid3);
r_l->num_entries = num_entries;
r_l->undoc_buffer = 1;
r_l->num_entries2 = num_entries;
for (i = 0; i < num_entries; i++)
{
make_dom_rid2(&(r_l->dom_rid[i]), dom_rids[i]);
}
r_l->num_entries3 = num_entries;
}
/***************************************************************************
make_reply_lookup_sids
***************************************************************************/
static void make_reply_lookup_sids(LSA_R_LOOKUP_SIDS *r_l,
int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
char *dom_name, char *dom_sid,
char *other_sid1, char *other_sid2, char *other_sid3)
{
int i;
make_dom_ref(&(r_l->dom_ref), dom_name, dom_sid,
other_sid1, other_sid2, other_sid3);
r_l->num_entries = num_entries;
r_l->undoc_buffer = 1;
r_l->num_entries2 = num_entries;
for (i = 0; i < num_entries; i++)
{
make_dom_sid2(&(r_l->dom_sid[i]), dom_sids[i]);
}
r_l->num_entries3 = num_entries;
}
/***************************************************************************
lsa_reply_lookup_sids
***************************************************************************/
static int lsa_reply_lookup_sids(char *q, char *base,
int num_entries, fstring dom_sids[MAX_LOOKUP_SIDS],
char *dom_name, char *dom_sid,
char *other_sid1, char *other_sid2, char *other_sid3)
{
LSA_R_LOOKUP_SIDS r_l;
/* set up the LSA Lookup SIDs response */
make_reply_lookup_sids(&r_l, num_entries, dom_sids,
dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
r_l.status = 0x0;
/* store the response in the SMB stream */
q = lsa_io_r_lookup_sids(False, &r_l, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/***************************************************************************
lsa_reply_lookup_rids
***************************************************************************/
static int lsa_reply_lookup_rids(char *q, char *base,
int num_entries, uint32 dom_rids[MAX_LOOKUP_SIDS],
char *dom_name, char *dom_sid,
char *other_sid1, char *other_sid2, char *other_sid3)
{
LSA_R_LOOKUP_RIDS r_l;
/* set up the LSA Lookup RIDs response */
make_reply_lookup_rids(&r_l, num_entries, dom_rids,
dom_name, dom_sid, other_sid1, other_sid2, other_sid3);
r_l.status = 0x0;
/* store the response in the SMB stream */
q = lsa_io_r_lookup_rids(False, &r_l, q, base, 4, 0);
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/***************************************************************************
api_lsa_open_policy
***************************************************************************/
static void api_lsa_open_policy( char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_OPEN_POL q_o;
/* grab the server, object attributes and desired access flag...*/
lsa_io_q_open_pol(True, &q_o, data + 0x18, data, 4, 0);
/* lkclXXXX having decoded it, ignore all fields in the open policy! */
/* return a 20 byte policy handle */
*rdata_len = lsa_reply_open_policy(*rdata + 0x18, *rdata);
}
/***************************************************************************
api_lsa_query_info
***************************************************************************/
static void api_lsa_query_info( char *param, char *data,
char **rdata, int *rdata_len )
{
LSA_Q_QUERY_INFO q_i;
pstring dom_name;
pstring dom_sid;
/* grab the info class and policy handle */
lsa_io_q_query(True, &q_i, data + 0x18, data, 4, 0);
pstrcpy(dom_name, lp_workgroup());
pstrcpy(dom_sid , lp_domain_sid());
/* construct reply. return status is always 0x0 */
*rdata_len = lsa_reply_query_info(&q_i, *rdata + 0x18, *rdata,
dom_name, dom_sid);
}
/***************************************************************************
api_lsa_lookup_sids
***************************************************************************/
static void api_lsa_lookup_sids( char *param, char *data,
char **rdata, int *rdata_len )
{
int i;
LSA_Q_LOOKUP_SIDS q_l;
pstring dom_name;
pstring dom_sid;
fstring dom_sids[MAX_LOOKUP_SIDS];
/* grab the info class and policy handle */
lsa_io_q_lookup_sids(True, &q_l, data + 0x18, data, 4, 0);
pstrcpy(dom_name, lp_workgroup());
pstrcpy(dom_sid , lp_domain_sid());
/* convert received SIDs to strings, so we can do them. */
for (i = 0; i < q_l.num_entries; i++)
{
fstrcpy(dom_sids[i], dom_sid_to_string(&(q_l.dom_sids[i])));
}
/* construct reply. return status is always 0x0 */
*rdata_len = lsa_reply_lookup_sids(*rdata + 0x18, *rdata,
q_l.num_entries, dom_sids, /* text-converted SIDs */
dom_name, dom_sid, /* domain name, domain SID */
"S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */
}
/***************************************************************************
api_lsa_lookup_names
***************************************************************************/
static void api_lsa_lookup_names( char *param, char *data,
char **rdata, int *rdata_len )
{
int i;
LSA_Q_LOOKUP_RIDS q_l;
pstring dom_name;
pstring dom_sid;
uint32 dom_rids[MAX_LOOKUP_SIDS];
uint32 dummy_g_rid;
/* grab the info class and policy handle */
lsa_io_q_lookup_rids(True, &q_l, data + 0x18, data, 4, 0);
pstrcpy(dom_name, lp_workgroup());
pstrcpy(dom_sid , lp_domain_sid());
/* convert received RIDs to strings, so we can do them. */
for (i = 0; i < q_l.num_entries; i++)
{
char *user_name = unistr2(q_l.lookup_name[i].str.buffer);
if (!name_to_rid(user_name, &dom_rids[i], &dummy_g_rid))
{
/* WHOOPS! we should really do something about this... */
dom_rids[i] = 0;
}
}
/* construct reply. return status is always 0x0 */
*rdata_len = lsa_reply_lookup_rids(*rdata + 0x18, *rdata,
q_l.num_entries, dom_rids, /* text-converted SIDs */
dom_name, dom_sid, /* domain name, domain SID */
"S-1-1", "S-1-3", "S-1-5"); /* the three other SIDs */
}
/***************************************************************************
api_ntLsarpcTNP
***************************************************************************/
BOOL api_ntLsarpcTNP(int cnum,int uid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
{
RPC_HDR_RR hdr;
if (data == NULL)
{
DEBUG(2,("api_ntLsarpcTNP: NULL data received\n"));
return False;
}
smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
DEBUG(4,("lsarpc TransactNamedPipe op %x\n",hdr.opnum));
switch (hdr.opnum)
{
case LSA_OPENPOLICY:
{
DEBUG(3,("LSA_OPENPOLICY\n"));
api_lsa_open_policy(param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_QUERYINFOPOLICY:
{
DEBUG(3,("LSA_QUERYINFOPOLICY\n"));
api_lsa_query_info(param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_ENUMTRUSTDOM:
{
char *q = *rdata + 0x18;
DEBUG(3,("LSA_ENUMTRUSTDOM\n"));
initrpcreply(data, *rdata);
SIVAL(q, 0, 0); /* enumeration context */
SIVAL(q, 0, 4); /* entries read */
SIVAL(q, 0, 8); /* trust information */
q += 12;
endrpcreply(data, *rdata, q-*rdata, 0x8000001a, rdata_len);
break;
}
case LSA_CLOSE:
{
char *q;
DEBUG(3,("LSA_CLOSE\n"));
initrpcreply(data, *rdata);
q = *rdata + 0x18;
SIVAL(q, 0, 0); q += 4;
SIVAL(q, 0, 0); q += 4;
SIVAL(q, 0, 0); q += 4;
SIVAL(q, 0, 0); q += 4;
SIVAL(q, 0, 0); q += 4;
endrpcreply(data, *rdata, q-*rdata, 0, rdata_len);
break;
}
case LSA_OPENSECRET:
{
char *q = *rdata + 0x18;
DEBUG(3,("LSA_OPENSECRET\n"));
initrpcreply(data, *rdata);
SIVAL(q, 0, 0);
SIVAL(q, 0, 4);
SIVAL(q, 0, 8);
SIVAL(q, 0, 12);
SIVAL(q, 0, 16);
q += 20;
endrpcreply(data, *rdata, q-*rdata, 0xc000034, rdata_len);
break;
}
case LSA_LOOKUPSIDS:
{
DEBUG(3,("LSA_OPENSECRET\n"));
api_lsa_lookup_sids(param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case LSA_LOOKUPNAMES:
{
DEBUG(3,("LSA_LOOKUPNAMES\n"));
api_lsa_lookup_names(param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
default:
{
DEBUG(4, ("NTLSARPC, unknown code: %lx\n", hdr.opnum));
break;
}
}
return True;
}
#endif /* NTDOMAIN */

View File

@ -1,264 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Pipe SMB reply routines - srvsvc pipe
Copyright (C) Andrew Tridgell 1992-1997,
Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
Copyright (C) Paul Ashton 1997.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
#include "trans2.h"
#include "nterr.h"
extern int DEBUGLEVEL;
/*******************************************************************
********************************************************************/
static void make_srv_share_info1_str(SH_INFO_1_STR *sh1, char *net_name, char *remark)
{
if (sh1 == NULL) return;
DEBUG(5,("make_srv_share_info1_str: %s %s\n", net_name, remark));
make_unistr2(&(sh1->uni_netname), net_name, strlen(net_name)+1);
make_unistr2(&(sh1->uni_remark ), remark , strlen(remark )+1);
}
/*******************************************************************
********************************************************************/
static void make_srv_share_info1(SH_INFO_1 *sh1, char *net_name, uint32 type, char *remark)
{
if (sh1 == NULL) return;
DEBUG(5,("make_srv_share_info1_str: %s %8x %s\n", net_name, type, remark));
sh1->ptr_netname = net_name != NULL ? 1 : 0;
sh1->type = type;
sh1->ptr_remark = remark != NULL ? 1 : 0;
}
/*******************************************************************
fill in a share info level 1 structure.
this function breaks the rule that i'd like to be in place, namely
it doesn't receive its data as arguments: it has to call lp_xxxx()
functions itself. yuck.
this function is identical to api_RNetShareEnum(). maybe it even
generates the same output! (too much to hope for, really...)
********************************************************************/
static void make_srv_share_1_ctr(SHARE_INFO_1_CTR *ctr)
{
int snum;
int num_entries = 0;
int svcs = lp_numservices();
if (ctr == NULL) return;
DEBUG(5,("make_srv_share_1_ctr\n"));
for (snum = 0; snum < svcs && num_entries < MAX_SHARE_ENTRIES; num_entries++, snum++)
{
int len_net_name;
pstring net_name;
pstring remark;
uint32 type;
if (lp_browseable(snum) && lp_snum_ok(snum))
{
/* see ipc.c:fill_share_info() */
pstrcpy(net_name, lp_servicename(snum));
pstrcpy(remark , lp_comment (snum));
len_net_name = strlen(net_name);
/* work out the share type */
type = STYPE_DISKTREE;
if (lp_print_ok(snum)) type = STYPE_PRINTQ;
if (strequal("IPC$", net_name)) type = STYPE_IPC;
if (net_name[len_net_name] == '$') type |= STYPE_HIDDEN;
make_srv_share_info1 (&(ctr->info_1 [num_entries]), net_name, type, remark);
make_srv_share_info1_str(&(ctr->info_1_str[num_entries]), net_name, remark);
}
}
ctr->num_entries_read = num_entries;
ctr->ptr_share_info = num_entries > 0 ? 1 : 0;
ctr->num_entries_read2 = num_entries;
ctr->num_entries_read3 = num_entries;
ctr->padding = 0;
}
/*******************************************************************
********************************************************************/
static void make_srv_net_share_enum(SRV_R_NET_SHARE_ENUM *r_n,
int share_level, int switch_value, int status)
{
DEBUG(5,("make_srv_net_share_enum: %d\n", __LINE__));
r_n->share_level = share_level;
r_n->switch_value = switch_value;
r_n->status = status;
switch (switch_value)
{
case 1:
{
make_srv_share_1_ctr(&(r_n->share.info1));
r_n->ptr_share_info = r_n->share.info1.num_entries_read > 0 ? 1 : 0;
break;
}
default:
{
DEBUG(5,("make_srv_net_share_enum: unsupported switch value %d\n",
switch_value));
r_n->ptr_share_info = 0;
break;
}
}
}
/*******************************************************************
********************************************************************/
static int srv_reply_net_share_enum(SRV_Q_NET_SHARE_ENUM *q_n,
char *q, char *base,
int status)
{
SRV_R_NET_SHARE_ENUM r_n;
DEBUG(5,("srv_net_share_enum: %d\n", __LINE__));
/* set up the */
make_srv_net_share_enum(&r_n, q_n->share_level, q_n->switch_value, status);
/* store the response in the SMB stream */
q = srv_io_r_net_share_enum(False, &r_n, q, base, 4, 0);
DEBUG(5,("srv_srv_pwset: %d\n", __LINE__));
/* return length of SMB data stored */
return PTR_DIFF(q, base);
}
/*******************************************************************
********************************************************************/
static void api_srv_net_share_info( char *param, char *data,
char **rdata, int *rdata_len )
{
SRV_Q_NET_SHARE_ENUM q_n;
/* grab the net share enum */
srv_io_q_net_share_enum(True, &q_n, data + 0x18, data, 4, 0);
/* XXXX push the reply buffer size up a bit, and hope it's sufficient */
/* for the current maximum limit of 32 share entries */
*rdata_len = 4096;
*rdata = REALLOC(*rdata, *rdata_len);
/* construct reply. always indicate success */
*rdata_len = srv_reply_net_share_enum(&q_n, *rdata + 0x18, *rdata, 0x0);
}
/*******************************************************************
receives a srvsvc pipe and responds.
********************************************************************/
BOOL api_srvsvcTNP(int cnum,int uid, char *param,char *data,
int mdrcnt,int mprcnt,
char **rdata,char **rparam,
int *rdata_len,int *rparam_len)
{
RPC_HDR_RR hdr;
if (data == NULL)
{
DEBUG(2,("api_srvsvcTNP: NULL data received\n"));
return False;
}
smb_io_rpc_hdr_rr(True, &hdr, data, data, 4, 0);
DEBUG(4,("srvsvc TransactNamedPipe op %x\n",hdr.opnum));
switch (hdr.opnum)
{
case NETSHAREENUM:
{
api_srv_net_share_info( param, data, rdata, rdata_len);
create_rpc_reply(hdr.hdr.call_id, *rdata, *rdata_len);
break;
}
case NETSERVERGETINFO:
{
extern pstring myname;
char *q;
char *servername;
uint32 level;
UNISTR2 uni_str;
q = data + 0x18;
servername = q + 16;
q = skip_unicode_string(servername,1);
if (strlen(unistr(servername)) % 2 == 0)
q += 2;
level = IVAL(q, 0); q += 4;
/* ignore the rest for the moment */
initrpcreply(data, *rdata);
q = *rdata + 0x18;
SIVAL(q, 0, 101); q += 4; /* switch value */
SIVAL(q, 0, 2); q += 4; /* bufptr */
SIVAL(q, 0, 0x1f4); q += 4; /* platform id */
SIVAL(q, 0, 2); q += 4; /* bufptr for name */
SIVAL(q, 0, 5); q += 4; /* major version */
SIVAL(q, 0, 4); q += 4; /* minor version == 5.4 */
SIVAL(q, 0, 0x4100B); q += 4; /* type */
SIVAL(q, 0, 2); q += 4; /* comment */
get_myname(myname,NULL);
make_unistr2(&uni_str, myname, strlen(myname));
q = smb_io_unistr2(False, &uni_str, q, *rdata, 4, 0);
make_unistr2(&uni_str, lp_serverstring(), strlen(lp_serverstring()));
q = smb_io_unistr2(False, &uni_str, q, *rdata, 4, 0);
q = align_offset(q, *rdata, 4);
endrpcreply(data, *rdata, q-*rdata, 0, rdata_len);
break;
}
default:
{
DEBUG(4, ("srvsvc, unknown code: %lx\n", hdr.opnum));
break;
}
}
return(True);
}

View File

@ -1,235 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Pipe SMB utility routines
Copyright (C) Andrew Tridgell 1992-1997,
Copyright (C) Luke Kenneth Casson Leighton 1996-1997.
Copyright (C) Paul Ashton 1997.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This file handles reply_ calls on named pipes that the server
makes to handle specific protocols
*/
#include "includes.h"
#include "trans2.h"
extern int DEBUGLEVEL;
/* this function is due to be replaced */
void initrpcreply(char *inbuf, char *q)
{
uint32 callid;
SCVAL(q, 0, 5); q++; /* RPC version 5 */
SCVAL(q, 0, 0); q++; /* minor version 0 */
SCVAL(q, 0, 2); q++; /* RPC response packet */
SCVAL(q, 0, 3); q++; /* first frag + last frag */
RSIVAL(q, 0, 0x10000000); q += 4; /* packed data representation */
RSSVAL(q, 0, 0); q += 2; /* fragment length, fill in later */
SSVAL(q, 0, 0); q += 2; /* authentication length */
callid = RIVAL(inbuf, 12);
RSIVAL(q, 0, callid); q += 4; /* call identifier - match incoming RPC */
SIVAL(q, 0, 0x18); q += 4; /* allocation hint (no idea) */
SSVAL(q, 0, 0); q += 2; /* presentation context identifier */
SCVAL(q, 0, 0); q++; /* cancel count */
SCVAL(q, 0, 0); q++; /* reserved */
}
/* this function is due to be replaced */
void endrpcreply(char *inbuf, char *q, int datalen, int rtnval, int *rlen)
{
SSVAL(q, 8, datalen + 4);
SIVAL(q,0x10,datalen+4-0x18); /* allocation hint */
SIVAL(q, datalen, rtnval);
*rlen = datalen + 4;
{ int fd; fd = open("/tmp/rpc", O_RDWR); write(fd, q, datalen + 4); }
}
/* Group and User RID username mapping function */
BOOL name_to_rid(char *user_name, uint32 *u_rid, uint32 *g_rid)
{
struct passwd *pw = Get_Pwnam(user_name, False);
if (u_rid == NULL || g_rid == NULL || user_name == NULL)
{
return False;
}
if (!pw)
{
DEBUG(1,("Username %s is invalid on this system\n", user_name));
return False;
}
if (user_in_list(user_name, lp_domain_guest_users()))
{
*u_rid = DOMAIN_USER_RID_GUEST;
}
else if (user_in_list(user_name, lp_domain_admin_users()))
{
*u_rid = DOMAIN_USER_RID_ADMIN;
}
else
{
/* turn the unix UID into a Domain RID. this is what the posix
sub-system does (adds 1000 to the uid) */
*u_rid = (uint32)(pw->pw_uid + 1000);
}
/* absolutely no idea what to do about the unix GID to Domain RID mapping */
*g_rid = (uint32)(pw->pw_gid + 1000);
return True;
}
/* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
char *dom_sid_to_string(DOM_SID *sid)
{
static pstring sidstr;
char subauth[16];
int i;
uint32 ia = (sid->id_auth[5]) +
(sid->id_auth[4] << 8 ) +
(sid->id_auth[3] << 16) +
(sid->id_auth[2] << 24);
sprintf(sidstr, "S-%d-%d", sid->sid_rev_num, ia);
for (i = 0; i < sid->num_auths; i++)
{
sprintf(subauth, "-%d", sid->sub_auths[i]);
strcat(sidstr, subauth);
}
DEBUG(5,("dom_sid_to_string returning %s\n", sidstr));
return sidstr;
}
int make_dom_sids(char *sids_str, DOM_SID *sids, int max_sids)
{
char *ptr;
pstring s2;
int count;
DEBUG(4,("make_dom_sids: %s\n", sids_str));
if (sids_str == NULL || *sids_str == 0) return 0;
for (count = 0, ptr = sids_str; next_token(&ptr, s2, NULL) && count < max_sids; count++)
{
make_dom_sid(&sids[count], s2);
}
return count;
}
/* array lookup of well-known RID aliases. the purpose of these escapes me.. */
/* XXXX this structure should not have the well-known RID groups added to it,
i.e the DOMAIN_GROUP_RID_ADMIN/USER/GUEST. */
static struct
{
uint32 rid;
char *rid_name;
} rid_lookups[] =
{
{ DOMAIN_ALIAS_RID_ADMINS , "admins" },
{ DOMAIN_ALIAS_RID_USERS , "users" },
{ DOMAIN_ALIAS_RID_GUESTS , "guests" },
{ DOMAIN_ALIAS_RID_POWER_USERS , "power_users" },
{ DOMAIN_ALIAS_RID_ACCOUNT_OPS , "account_ops" },
{ DOMAIN_ALIAS_RID_SYSTEM_OPS , "system_ops" },
{ DOMAIN_ALIAS_RID_PRINT_OPS , "print_ops" },
{ DOMAIN_ALIAS_RID_BACKUP_OPS , "backup_ops" },
{ DOMAIN_ALIAS_RID_REPLICATOR , "replicator" },
{ 0 , NULL }
};
int make_dom_gids(char *gids_str, DOM_GID *gids)
{
char *ptr;
pstring s2;
int count;
DEBUG(4,("make_dom_gids: %s\n", gids_str));
if (gids_str == NULL || *gids_str == 0) return 0;
for (count = 0, ptr = gids_str; next_token(&ptr, s2, NULL) && count < LSA_MAX_GROUPS; count++)
{
/* the entries are of the form GID/ATTR, ATTR being optional.*/
char *attr;
uint32 rid = 0;
int i;
attr = strchr(s2,'/');
if (attr) *attr++ = 0;
if (!attr || !*attr) attr = "7"; /* default value for attribute is 7 */
/* look up the RID string and see if we can turn it into a rid number */
for (i = 0; rid_lookups[i].rid_name != NULL; i++)
{
if (strequal(rid_lookups[i].rid_name, s2))
{
rid = rid_lookups[i].rid;
break;
}
}
if (rid == 0) rid = atoi(s2);
if (rid == 0)
{
DEBUG(1,("make_dom_gids: unknown well-known alias RID %s/%s\n",
s2, attr));
count--;
}
else
{
gids[count].g_rid = rid;
gids[count].attr = atoi(attr);
DEBUG(5,("group id: %d attr: %d\n",
gids[count].g_rid,
gids[count].attr));
}
}
return count;
}
int create_rpc_request(uint32 call_id, uint8 op_num, char *q, int data_len)
{
RPC_HDR_RR hdr;
make_rpc_hdr_rr(&hdr, RPC_REQUEST, call_id, data_len, op_num);
return smb_io_rpc_hdr_rr(False, &hdr, q, q, 4, 0) - q;
}
int create_rpc_reply(uint32 call_id, char *q, int data_len)
{
RPC_HDR_RR hdr;
make_rpc_hdr_rr(&hdr, RPC_RESPONSE, call_id, data_len, 0);
return smb_io_rpc_hdr_rr(False, &hdr, q, q, 4, 0) - q;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,205 +1 @@
/*
Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
Copyright (C) Andrew Tridgell 1994 - 1997
Copyright (C) Luke Kenneth Casson Leighton 1996 - 1997
Copyright (C) Paul Ashton 1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
extern int DEBUGLEVEL;
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* srv_io_share_info1_str(BOOL io, SH_INFO_1_STR *sh1, char *q, char *base, int align, int depth)
{
if (sh1 == NULL) return NULL;
DEBUG(5,("%s%04x srv_io_share_info1_str\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
q = smb_io_unistr2(io, &(sh1->uni_netname), q, base, align, depth);
q = smb_io_unistr2(io, &(sh1->uni_remark ), q, base, align, depth);
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* srv_io_share_info1(BOOL io, SH_INFO_1 *sh1, char *q, char *base, int align, int depth)
{
if (sh1 == NULL) return NULL;
DEBUG(5,("%s%04x srv_io_share_info1\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("ptr_netname", depth, base, io, q, sh1->ptr_netname); q += 4;
DBG_RW_IVAL("type ", depth, base, io, q, sh1->type ); q += 4;
DBG_RW_IVAL("ptr_remark ", depth, base, io, q, sh1->ptr_remark); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* srv_io_share_1_ctr(BOOL io, SHARE_INFO_1_CTR *ctr, char *q, char *base, int align, int depth)
{
if (ctr == NULL) return NULL;
DEBUG(5,("%s%04x srv_io_share_1_ctr\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("num_entries_read", depth, base, io, q, ctr->num_entries_read); q += 4;
DBG_RW_IVAL("ptr_share_info", depth, base, io, q, ctr->ptr_share_info); q += 4;
if (ctr->ptr_share_info != 0)
{
int i;
int num_entries = ctr->num_entries_read;
if (num_entries > MAX_SHARE_ENTRIES)
{
num_entries = MAX_SHARE_ENTRIES; /* report this! */
}
DBG_RW_IVAL("num_entries_read2", depth, base, io, q, ctr->num_entries_read2); q += 4;
for (i = 0; i < num_entries; i++)
{
q = srv_io_share_info1(io, &(ctr->info_1[i]), q, base, align, depth);
}
for (i = 0; i < num_entries; i++)
{
q = srv_io_share_info1_str(io, &(ctr->info_1_str[i]), q, base, align, depth);
}
q = align_offset(q, base, align);
DBG_RW_IVAL("num_entries_read3", depth, base, io, q, ctr->num_entries_read3); q += 4;
DBG_RW_IVAL("padding ", depth, base, io, q, ctr->padding); q += 4;
}
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* srv_io_q_net_share_enum(BOOL io, SRV_Q_NET_SHARE_ENUM *q_n, char *q, char *base, int align, int depth)
{
if (q_n == NULL) return NULL;
DEBUG(5,("%s%04x srv_io_q_net_share_enum\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("ptr_srv_name", depth, base, io, q, q_n->ptr_srv_name); q += 4;
q = smb_io_unistr2(io, &(q_n->uni_srv_name), q, base, align, depth);
q = align_offset(q, base, align);
DBG_RW_IVAL("share_level ", depth, base, io, q, q_n->share_level); q += 4;
DBG_RW_IVAL("switch_value ", depth, base, io, q, q_n->switch_value); q += 4;
DBG_RW_IVAL("ptr_share_info", depth, base, io, q, q_n->ptr_share_info); q += 4;
if (q_n->ptr_share_info != 0)
{
switch (q_n->switch_value)
{
case 1:
{
q = srv_io_share_1_ctr(io, &(q_n->share.info1), q, base, align, depth);
break;
}
default:
{
DEBUG(5,("%s% no share info at switch_value %d\n",
tab_depth(depth), q_n->switch_value));
break;
}
}
}
DBG_RW_IVAL("preferred_len ", depth, base, io, q, q_n->preferred_len); q += 4;
return q;
}
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* srv_io_r_net_share_enum(BOOL io, SRV_R_NET_SHARE_ENUM *r_n, char *q, char *base, int align, int depth)
{
if (r_n == NULL) return NULL;
DEBUG(5,("%s%04x srv_io_q_net_share_enum\n", tab_depth(depth), PTR_DIFF(q, base)));
depth++;
q = align_offset(q, base, align);
DBG_RW_IVAL("share_level ", depth, base, io, q, r_n->share_level); q += 4;
DBG_RW_IVAL("switch_value ", depth, base, io, q, r_n->switch_value); q += 4;
DBG_RW_IVAL("ptr_share_info", depth, base, io, q, r_n->ptr_share_info); q += 4;
if (r_n->ptr_share_info != 0)
{
switch (r_n->switch_value)
{
case 1:
{
q = srv_io_share_1_ctr(io, &(r_n->share.info1), q, base, align, depth);
break;
}
default:
{
DEBUG(5,("%s% no share info at switch_value %d\n",
tab_depth(depth), r_n->switch_value));
break;
}
}
}
DBG_RW_IVAL("status ", depth, base, io, q, r_n->status); q += 4;
return q;
}
#if 0
/*******************************************************************
reads or writes a structure.
********************************************************************/
char* lsa_io_(BOOL io, *, char *q, char *base, int align, int depth)
{
if (== NULL) return NULL;
q = align_offset(q, base, align);
DBG_RW_IVAL("", depth, base, io, q, ); q += 4;
return q;
}
#endif