2 Unix SMB/Netbios implementation.
4 Pipe SMB reply routines
5 Copyright (C) Andrew Tridgell 1992-1997,
7 Luke Kenneth Casson Leighton 1996-1997.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 This file handles reply_ calls on named pipes that the server
25 makes to handle specific protocols
33 #define PIPE "\\PIPE\\"
34 #define PIPELEN strlen(PIPE)
36 #define REALLOC(ptr,size) Realloc(ptr,MAX((size),4*1024))
38 /* look in server.c for some explanation of these variables */
40 extern int DEBUGLEVEL;
41 extern int chain_fnum;
42 extern char magic_char;
43 extern connection_struct Connections[];
44 extern files_struct Files[];
45 extern BOOL case_sensitive;
46 extern pstring sesssetup_user;
48 extern fstring myworkgroup;
50 /* this macro should always be used to extract an fnum (smb_fid) from
51 a packet to ensure chaining works correctly */
52 #define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
54 char * known_pipes [] =
63 /****************************************************************************
64 reply to an open and X on a named pipe
66 In fact what we do is to open a regular file with the same name in
67 /tmp. This can then be closed as normal. Reading and writing won't
68 make much sense, but will do *something*. The real reason for this
69 support is to be able to do transactions on them (well, on lsarpc
70 for domain login purposes...).
72 This code is basically stolen from reply_open_and_X with some
73 wrinkles to handle pipes.
74 ****************************************************************************/
75 int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
78 int cnum = SVAL(inbuf,smb_tid);
80 int smb_mode = SVAL(inbuf,smb_vwv3);
81 int smb_attr = SVAL(inbuf,smb_vwv5);
83 int open_flags = SVAL(inbuf,smb_vwv2);
84 int smb_sattr = SVAL(inbuf,smb_vwv4);
85 uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
87 int smb_ofun = SVAL(inbuf,smb_vwv8);
89 int size=0,fmode=0,mtime=0,rmode=0;
93 BOOL bad_path = False;
95 /* XXXX we need to handle passed times, sattr and flags */
96 pstrcpy(fname,smb_buf(inbuf));
98 /* If the name doesn't start \PIPE\ then this is directed */
99 /* at a mailslot or something we really, really don't understand, */
100 /* not just something we really don't understand. */
101 if ( strncmp(fname,PIPE,PIPELEN) != 0 )
102 return(ERROR(ERRSRV,ERRaccess));
104 DEBUG(4,("Opening pipe %s.\n", fname));
106 /* Strip \PIPE\ off the name. */
107 pstrcpy(fname,smb_buf(inbuf) + PIPELEN);
109 /* See if it is one we want to handle. */
110 for( i = 0; known_pipes[i] ; i++ )
111 if( strcmp(fname,known_pipes[i]) == 0 )
114 if ( known_pipes[i] == NULL )
115 return(ERROR(ERRSRV,ERRaccess));
117 /* Known pipes arrive with DIR attribs. Remove it so a regular file */
118 /* can be opened and add it in after the open. */
119 DEBUG(3,("Known pipe %s opening.\n",fname));
121 Connections[cnum].read_only = 0;
122 smb_ofun |= 0x10; /* Add Create it not exists flag */
124 unix_convert(fname,cnum,0,&bad_path);
126 fnum = find_free_file();
128 return(ERROR(ERRSRV,ERRnofids));
130 if (!check_name(fname,cnum))
131 return(UNIXERROR(ERRDOS,ERRnoaccess));
133 unixmode = unix_mode(cnum,smb_attr);
135 open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
136 0, &rmode,&smb_action);
138 if (!Files[fnum].open)
140 /* Change the error code if bad_path was set. */
141 if((errno == ENOENT) && bad_path)
143 unix_ERR_class = ERRDOS;
144 unix_ERR_code = ERRbadpath;
146 return(UNIXERROR(ERRDOS,ERRnoaccess));
149 if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
151 return(ERROR(ERRDOS,ERRnoaccess));
155 fmode = dos_mode(cnum,fname,&sbuf);
156 mtime = sbuf.st_mtime;
159 return(ERROR(ERRDOS,ERRnoaccess));
162 /* Prepare the reply */
163 set_message(outbuf,15,0,True);
165 /* Put things back the way they were. */
166 Connections[cnum].read_only = 1;
168 /* Mark the opened file as an existing named pipe in message mode. */
169 SSVAL(outbuf,smb_vwv9,2);
170 SSVAL(outbuf,smb_vwv10,0xc700);
173 DEBUG(4,("Resetting open result to open from create.\n"));
177 SSVAL(outbuf,smb_vwv2,fnum);
178 SSVAL(outbuf,smb_vwv3,fmode);
179 put_dos_date3(outbuf,smb_vwv4,mtime);
180 SIVAL(outbuf,smb_vwv6,size);
181 SSVAL(outbuf,smb_vwv8,rmode);
182 SSVAL(outbuf,smb_vwv11,smb_action);
186 DEBUG(4,("Opened pipe %s with handle %d, saved name %s.\n",
187 fname, fnum, Files[fnum].name));
189 return chain_reply(inbuf,outbuf,length,bufsize);
193 /****************************************************************************
196 SetNamedPipeHandleState on \PIPE\lsarpc. We can't really do much here,
197 so just blithely return True. This is really only for NT domain stuff,
198 we we're only handling that - don't assume Samba now does complete
200 ****************************************************************************/
201 BOOL api_LsarpcSNPHS(int cnum,int uid, char *param,char *data,
202 int mdrcnt,int mprcnt,
203 char **rdata,char **rparam,
204 int *rdata_len,int *rparam_len)
208 id = param[0] + (param[1] << 8);
209 DEBUG(4,("lsarpc SetNamedPipeHandleState to code %x\n",id));
214 /****************************************************************************
217 TransactNamedPipe on \PIPE\lsarpc.
218 ****************************************************************************/
219 static void LsarpcTNP1(char *data,char **rdata, int *rdata_len)
221 uint32 dword1, dword2;
222 char pname[] = "\\PIPE\\lsass";
224 /* All kinds of mysterious numbers here */
226 *rdata = REALLOC(*rdata,*rdata_len);
228 dword1 = IVAL(data,0xC);
229 dword2 = IVAL(data,0x10);
231 SIVAL(*rdata,0,0xc0005);
232 SIVAL(*rdata,4,0x10);
233 SIVAL(*rdata,8,0x44);
234 SIVAL(*rdata,0xC,dword1);
236 SIVAL(*rdata,0x10,dword2);
237 SIVAL(*rdata,0x14,0x15);
238 SSVAL(*rdata,0x18,sizeof(pname));
239 strcpy(*rdata + 0x1a,pname);
240 SIVAL(*rdata,0x28,1);
241 memcpy(*rdata + 0x30, data + 0x34, 0x14);
244 static void LsarpcTNP2(char *data,char **rdata, int *rdata_len)
248 /* All kinds of mysterious numbers here */
250 *rdata = REALLOC(*rdata,*rdata_len);
252 dword1 = IVAL(data,0xC);
254 SIVAL(*rdata,0,0x03020005);
255 SIVAL(*rdata,4,0x10);
256 SIVAL(*rdata,8,0x30);
257 SIVAL(*rdata,0xC,dword1);
258 SIVAL(*rdata,0x10,0x18);
259 SIVAL(*rdata,0x1c,0x44332211);
260 SIVAL(*rdata,0x20,0x88776655);
261 SIVAL(*rdata,0x24,0xCCBBAA99);
262 SIVAL(*rdata,0x28,0x11FFEEDD);
265 static void LsarpcTNP3(char *data,char **rdata, int *rdata_len)
269 char * workgroup = myworkgroup;
270 int wglen = strlen(workgroup);
273 /* All kinds of mysterious numbers here */
274 *rdata_len = 90 + 2 * wglen;
275 *rdata = REALLOC(*rdata,*rdata_len);
277 dword1 = IVAL(data,0xC);
278 word1 = SVAL(data,0x2C);
280 SIVAL(*rdata,0,0x03020005);
281 SIVAL(*rdata,4,0x10);
282 SIVAL(*rdata,8,0x60);
283 SIVAL(*rdata,0xC,dword1);
284 SIVAL(*rdata,0x10,0x48);
285 SSVAL(*rdata,0x18,0x5988); /* This changes */
286 SSVAL(*rdata,0x1A,0x15);
287 SSVAL(*rdata,0x1C,word1);
288 SSVAL(*rdata,0x20,6);
289 SSVAL(*rdata,0x22,8);
290 SSVAL(*rdata,0x24,0x8E8); /* So does this */
291 SSVAL(*rdata,0x26,0x15);
292 SSVAL(*rdata,0x28,0x4D48); /* And this */
293 SSVAL(*rdata,0x2A,0x15);
294 SIVAL(*rdata,0x2C,4);
295 SIVAL(*rdata,0x34,wglen);
296 for ( i = 0 ; i < wglen ; i++ )
297 (*rdata)[0x38 + i * 2] = workgroup[i];
299 /* Now fill in the rest */
300 i = 0x38 + wglen * 2;
301 SSVAL(*rdata,i,0x648);
303 SIVAL(*rdata,i+6,0x401);
304 SSVAL(*rdata,i+0xC,0x500);
305 SIVAL(*rdata,i+0xE,0x15);
306 SIVAL(*rdata,i+0x12,0x2372FE1);
307 SIVAL(*rdata,i+0x16,0x7E831BEF);
308 SIVAL(*rdata,i+0x1A,0x4B454B2);
311 static void LsarpcTNP4(char *data,char **rdata, int *rdata_len)
315 /* All kinds of mysterious numbers here */
317 *rdata = REALLOC(*rdata,*rdata_len);
319 dword1 = IVAL(data,0xC);
321 SIVAL(*rdata,0,0x03020005);
322 SIVAL(*rdata,4,0x10);
323 SIVAL(*rdata,8,0x30);
324 SIVAL(*rdata,0xC,dword1);
325 SIVAL(*rdata,0x10,0x18);
329 BOOL api_LsarpcTNP(int cnum,int uid, char *param,char *data,
330 int mdrcnt,int mprcnt,
331 char **rdata,char **rparam,
332 int *rdata_len,int *rparam_len)
338 DEBUG(4,("lsarpc TransactNamedPipe id %lx\n",id));
342 LsarpcTNP1(data,rdata,rdata_len);
347 DEBUG(4,("\t- Suboperation %lx\n",id2));
351 LsarpcTNP2(data,rdata,rdata_len);
355 LsarpcTNP4(data,rdata,rdata_len);
359 LsarpcTNP3(data,rdata,rdata_len);
367 #if 0 /* HAVING TO DO THIS TO GET THINGS TO COMPILE - LUKE PLEASE CHECK THIS !!! */
370 PAXX: Someone fix above.
371 The above API is indexing RPC calls based on RPC flags and
372 fragment length. I've decided to do it based on operation number :-)
375 /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */
376 /* identauth >= 2^32 can be detected because it will be specified in hex */
377 static void make_dom_sid(DOM_SID *sid, char *domsid)
382 DEBUG(4,("netlogon domain SID: %s\n", domsid));
384 /* assume, but should check, that domsid starts "S-" */
385 p = strtok(domsid+2,"-");
386 sid->sid_no = atoi(p);
388 /* identauth in decimal should be < 2^32 */
389 /* identauth in hex should be >= 2^32 */
390 identauth = atoi(strtok(0,"-"));
392 DEBUG(4,("netlogon rev %d\n", sid->sid_no));
393 DEBUG(4,("netlogon %s ia %d\n", p, identauth));
397 sid->id_auth[2] = (identauth & 0xff000000) >> 24;
398 sid->id_auth[3] = (identauth & 0x00ff0000) >> 16;
399 sid->id_auth[4] = (identauth & 0x0000ff00) >> 8;
400 sid->id_auth[5] = (identauth & 0x000000ff);
404 while ((p = strtok(0, "-")) != NULL)
406 sid->sub_auths[sid->num_auths++] = atoi(p);
410 static void create_rpc_reply(RPC_HDR *hdr, uint32 call_id, int data_len)
412 if (hdr == NULL) return;
414 hdr->major = 5; /* RPC version 5 */
415 hdr->minor = 0; /* minor version 0 */
416 hdr->pkt_type = 2; /* RPC response packet */
417 hdr->frag = 3; /* first frag + last frag */
418 hdr->pack_type = 1; /* packed data representation */
419 hdr->frag_len = data_len; /* fragment length, fill in later */
420 hdr->auth_len = 0; /* authentication length */
421 hdr->call_id = call_id; /* call identifier - match incoming RPC */
422 hdr->alloc_hint = data_len - 0x18; /* allocation hint (no idea) */
423 hdr->context_id = 0; /* presentation context identifier */
424 hdr->cancel_count = 0; /* cancel count */
425 hdr->reserved = 0; /* reserved */
428 static void make_rpc_reply(char *inbuf, char *q, char *base, int data_len)
430 uint32 callid = RIVAL(inbuf, 12);
433 create_rpc_reply(&hdr, callid, data_len);
434 smb_io_rpc_hdr(False, &hdr, q, base, 4);
437 static int lsa_reply_open_policy(char *q, char *base)
442 /* set up the LSA QUERY INFO response */
443 bzero(&(r_o.pol.data), POL_HND_SIZE);
446 /* store the response in the SMB stream */
447 q = lsa_io_r_open_pol(False, &r_o, q, base, 4);
449 /* return length of SMB data stored */
453 static void make_uni_hdr(UNIHDR *hdr, int max_len, int len, uint16 terminate)
455 hdr->uni_max_len = max_len;
456 hdr->uni_str_len = len;
457 hdr->undoc = terminate;
460 static void make_unistr2(UNISTR2 *str, char *buf, int len, char terminate)
462 /* set up string lengths. add one if string is not null-terminated */
463 str->uni_max_len = len + (terminate != 0 ? 1 : 0);
465 str->uni_str_len = len;
467 /* store the string (null-terminated copy) */
468 PutUniCode((char *)str->buffer, buf);
470 /* overwrite the last character: some strings are terminated with 4 not 0 */
471 str->buffer[len] = (uint16)terminate;
474 static void make_dom_query(DOM_QUERY *d_q, char *dom_name, char *dom_sid)
476 int domlen = strlen(dom_name);
478 d_q->uni_dom_max_len = domlen * 2;
480 d_q->uni_dom_str_len = domlen * 2;
482 d_q->buffer_dom_name = 0; /* domain buffer pointer */
483 d_q->buffer_dom_sid = 0; /* domain sid pointer */
485 /* NOT null-terminated: 4-terminated instead! */
486 make_unistr2(&(d_q->uni_domain_name), dom_name, domlen, 4);
488 make_dom_sid(&(d_q->dom_sid), dom_sid);
491 static int lsa_reply_query_info(LSA_Q_QUERY_INFO *q_q, char *q, char *base,
492 char *dom_name, char *dom_sid)
495 LSA_R_QUERY_INFO r_q;
497 /* set up the LSA QUERY INFO response */
499 r_q.undoc_buffer = 1; /* not null */
500 r_q.info_class = q_q->info_class;
502 make_dom_query(&r_q.dom.id5, dom_name, dom_sid);
506 /* store the response in the SMB stream */
507 q = lsa_io_r_query(False, &r_q, q, base, 4);
509 /* return length of SMB data stored */
513 static void make_lsa_r_req_chal(LSA_R_REQ_CHAL *r_c, char chal[8], int status)
515 memcpy(r_c->srv_chal.data, chal, sizeof(r_c->srv_chal.data));
516 r_c->status = status;
521 /* PAXX: set these to random values */
522 for (int i = 0; i < 8; i+++)
528 static int lsa_reply_req_chal(LSA_Q_REQ_CHAL *q_c, char *q, char *base,
534 /* set up the LSA REQUEST CHALLENGE response */
536 make_lsa_r_req_chal(&r_c, chal, 0);
538 /* store the response in the SMB stream */
539 q = lsa_io_r_req_chal(False, &r_c, q, base, 4);
541 /* return length of SMB data stored */
545 static void make_lsa_chal(DOM_CHAL *cred, char resp_cred[8])
547 memcpy(cred->data, resp_cred, sizeof(cred->data));
550 static void make_lsa_r_auth_2(LSA_R_AUTH_2 *r_a,
551 char resp_cred[8], NEG_FLAGS *flgs, int status)
553 make_lsa_chal(&(r_a->srv_chal), resp_cred);
554 memcpy(&(r_a->srv_flgs), flgs, sizeof(r_a->srv_flgs));
555 r_a->status = status;
558 static int lsa_reply_auth_2(LSA_Q_AUTH_2 *q_a, char *q, char *base,
559 char resp_cred[8], int status)
564 /* set up the LSA AUTH 2 response */
566 make_lsa_r_auth_2(&r_a, resp_cred, &(q_a->clnt_flgs), status);
568 /* store the response in the SMB stream */
569 q = lsa_io_r_auth_2(False, &r_a, q, base, 4);
571 /* return length of SMB data stored */
575 static void make_lsa_dom_chal(DOM_CRED *cred, char srv_chal[8], UTIME srv_time)
577 make_lsa_chal(&(cred->challenge), srv_chal);
578 cred->timestamp = srv_time;
582 static void make_lsa_r_srv_pwset(LSA_R_SRV_PWSET *r_a,
583 char srv_chal[8], UTIME srv_time, int status)
585 make_lsa_dom_chal(&(r_a->srv_cred), srv_chal, srv_time);
586 r_a->status = status;
589 static int lsa_reply_srv_pwset(LSA_Q_SRV_PWSET *q_s, char *q, char *base,
590 char srv_cred[8], UTIME srv_time,
596 /* set up the LSA Server Password Set response */
597 make_lsa_r_srv_pwset(&r_s, srv_cred, srv_time, status);
599 /* store the response in the SMB stream */
600 q = lsa_io_r_srv_pwset(False, &r_s, q, base, 4);
602 /* return length of SMB data stored */
606 static void make_lsa_user_info(LSA_USER_INFO *usr,
610 NTTIME *kickoff_time,
611 NTTIME *pass_last_set_time,
612 NTTIME *pass_can_change_time,
613 NTTIME *pass_must_change_time,
637 char *other_sids) /* space-delimited set of SIDs */
639 /* only cope with one "other" sid, right now. */
640 /* need to count the number of space-delimited sids */
642 int num_other_sids = other_sids != NULL ? 1 : 0;
644 int len_user_name = strlen(user_name );
645 int len_full_name = strlen(full_name );
646 int len_logon_script = strlen(logon_script);
647 int len_profile_path = strlen(profile_path);
648 int len_home_dir = strlen(home_dir );
649 int len_dir_drive = strlen(dir_drive );
651 int len_logon_srv = strlen(logon_srv);
652 int len_logon_dom = strlen(logon_dom);
654 usr->undoc_buffer = 1; /* yes, we're bothering to put USER_INFO data here */
656 usr->logon_time = *logon_time;
657 usr->logoff_time = *logoff_time;
658 usr->kickoff_time = *kickoff_time;
659 usr->pass_last_set_time = *pass_last_set_time;
660 usr->pass_can_change_time = *pass_can_change_time;
661 usr->pass_must_change_time = *pass_must_change_time;
663 make_uni_hdr(&(usr->hdr_user_name ), len_user_name , len_user_name , 4);
664 make_uni_hdr(&(usr->hdr_full_name ), len_full_name , len_full_name , 4);
665 make_uni_hdr(&(usr->hdr_logon_script), len_logon_script, len_logon_script, 4);
666 make_uni_hdr(&(usr->hdr_profile_path), len_profile_path, len_profile_path, 4);
667 make_uni_hdr(&(usr->hdr_home_dir ), len_home_dir , len_home_dir , 4);
668 make_uni_hdr(&(usr->hdr_dir_drive ), len_dir_drive , len_dir_drive , 4);
670 usr->logon_count = logon_count;
671 usr->bad_pw_count = bad_pw_count;
673 usr->user_id = user_id;
674 usr->group_id = group_id;
675 usr->num_groups = num_groups;
676 usr->buffer_groups = num_groups ? 1 : 0; /* yes, we're bothering to put group info in */
677 usr->user_flgs = user_flgs;
679 if (sess_key != NULL)
681 memcpy(usr->sess_key, sess_key, sizeof(usr->sess_key));
685 bzero(usr->sess_key, sizeof(usr->sess_key));
688 make_uni_hdr(&(usr->hdr_logon_srv), len_logon_srv, len_logon_srv, 4);
689 make_uni_hdr(&(usr->hdr_logon_dom), len_logon_dom, len_logon_dom, 4);
691 usr->buffer_dom_id = dom_sid ? 1 : 0; /* yes, we're bothering to put a domain SID in */
693 bzero(usr->padding, sizeof(usr->padding));
695 usr->num_other_sids = num_other_sids;
696 usr->buffer_other_sids = num_other_sids != 0 ? 1 : 0;
698 make_unistr2(&(usr->uni_user_name ), user_name , len_user_name , 0);
699 make_unistr2(&(usr->uni_full_name ), full_name , len_full_name , 0);
700 make_unistr2(&(usr->uni_logon_script), logon_script, len_logon_script, 0);
701 make_unistr2(&(usr->uni_profile_path), profile_path, len_profile_path, 0);
702 make_unistr2(&(usr->uni_home_dir ), home_dir , len_home_dir , 0);
703 make_unistr2(&(usr->uni_dir_drive ), dir_drive , len_dir_drive , 0);
705 usr->num_groups2 = num_groups;
706 for (i = 0; i < num_groups; i++)
708 usr->gids[i] = gids[i];
711 make_unistr2(&(usr->uni_logon_srv), logon_srv, len_logon_srv, 0);
712 make_unistr2(&(usr->uni_logon_dom), logon_dom, len_logon_dom, 0);
714 make_dom_sid(&(usr->dom_sid), dom_sid);
715 make_dom_sid(&(usr->other_sids[0]), other_sids);
719 static int lsa_reply_sam_logon(LSA_Q_SAM_LOGON *q_s, char *q, char *base,
720 char srv_cred[8], UTIME srv_time,
721 LSA_USER_INFO *user_info)
726 /* XXXX maybe we want to say 'no', reject the client's credentials */
727 r_s.buffer_creds = 1; /* yes, we have valid server credentials */
728 make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time);
730 /* store the user information, if there is any. */
731 r_s.user = user_info;
732 r_s.buffer_user = user_info != NULL ? 1 : 0;
733 r_s.status = user_info != NULL ? 0 : (0xC000000|NT_STATUS_NO_SUCH_USER);
735 /* store the response in the SMB stream */
736 q = lsa_io_r_sam_logon(False, &r_s, q, base, 4);
738 /* return length of SMB data stored */
743 static int lsa_reply_sam_logoff(LSA_Q_SAM_LOGOFF *q_s, char *q, char *base,
744 char srv_cred[8], UTIME srv_time,
748 LSA_R_SAM_LOGOFF r_s;
750 /* XXXX maybe we want to say 'no', reject the client's credentials */
751 r_s.buffer_creds = 1; /* yes, we have valid server credentials */
752 make_lsa_dom_chal(&(r_s.srv_creds), srv_cred, srv_time);
756 /* store the response in the SMB stream */
757 q = lsa_io_r_sam_logoff(False, &r_s, q, base, 4);
759 /* return length of SMB data stored */
763 #endif /* LUKE PLEASE CHECK THIS !! */