diff options
Diffstat (limited to 'source/smbd/process.c')
-rw-r--r-- | source/smbd/process.c | 408 |
1 files changed, 210 insertions, 198 deletions
diff --git a/source/smbd/process.c b/source/smbd/process.c index 0f7cfd0e9cb..c34a146eab1 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -1,5 +1,6 @@ /* - Unix SMB/CIFS implementation. + Unix SMB/Netbios implementation. + Version 1.9. process incoming packets - main loop Copyright (C) Andrew Tridgell 1992-1998 @@ -20,6 +21,9 @@ #include "includes.h" +/* To be removed.... JRA */ +#define SMB_ALIGNMENT 1 + struct timeval smb_last_time; static char *InBuffer = NULL; @@ -42,8 +46,8 @@ extern int last_message; extern int global_oplock_break; extern userdom_struct current_user_info; extern int smb_read_error; -SIG_ATOMIC_T reload_after_sighup = 0; -SIG_ATOMIC_T got_sig_term = 0; +extern SIG_ATOMIC_T reload_after_sighup; +extern SIG_ATOMIC_T got_sig_term; extern BOOL global_machine_password_needs_changing; extern fstring global_myworkgroup; extern pstring global_myname; @@ -152,7 +156,7 @@ static void async_processing(char *buffer, int buffer_len) Returns False on timeout or error. Else returns True. -The timeout is in milliseconds +The timeout is in milli seconds ****************************************************************************/ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) @@ -258,6 +262,7 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) */ if (oplock_message_waiting(&fds)) { + DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n")); async_processing(buffer, buffer_len); /* * After async processing we must go and do the select again, as @@ -282,7 +287,7 @@ BOOL receive_next_smb(char *inbuf, int bufsize, int timeout) do { ret = receive_message_or_smb(inbuf,bufsize,timeout); - got_keepalive = (ret && (CVAL(inbuf,0) == SMBkeepalive)); + got_keepalive = (ret && (CVAL(inbuf,0) == 0x85)); } while (ret && got_keepalive); return ret; @@ -341,9 +346,9 @@ force write permissions on print services. functions. Any message that has a NULL function is unimplemented - please feel free to contribute implementations! */ -const static struct smb_message_struct +struct smb_message_struct { - const char *name; + char *name; int (*fn)(connection_struct *conn, char *, char *, int, int); int flags; } @@ -377,7 +382,7 @@ const static struct smb_message_struct /* 0x19 */ { NULL, NULL, 0 }, /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER}, /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER}, -/* 0x1c */ { "SMBreadBs",NULL,0 }, +/* 0x1c */ { "SMBreadBs",NULL,0}, /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER}, /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER}, /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER}, @@ -386,7 +391,7 @@ const static struct smb_message_struct /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE }, /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER }, /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER }, -/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC }, +/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC | QUEUE_IN_OPLOCK}, /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC}, /* 0x27 */ { "SMBioctl",reply_ioctl,0}, /* 0x28 */ { "SMBioctls",NULL,AS_USER}, @@ -509,7 +514,7 @@ const static struct smb_message_struct /* 0x9d */ { NULL, NULL, 0 }, /* 0x9e */ { NULL, NULL, 0 }, /* 0x9f */ { NULL, NULL, 0 }, -/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK}, +/* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC }, /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC }, /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC | QUEUE_IN_OPLOCK }, /* 0xa3 */ { NULL, NULL, 0 }, @@ -609,10 +614,9 @@ const static struct smb_message_struct }; /******************************************************************* - Dump a packet to a file. -********************************************************************/ - -static void smb_dump(const char *name, int type, char *data, ssize_t len) +dump a prs to a file + ********************************************************************/ +static void smb_dump(char *name, int type, char *data, ssize_t len) { int fd, i; pstring fname; @@ -636,171 +640,179 @@ static void smb_dump(const char *name, int type, char *data, ssize_t len) /**************************************************************************** - Do a switch on the message type, and return the response size + Do a switch on the message type, and return the response size. ****************************************************************************/ static int switch_message(int type,char *inbuf,char *outbuf,int size,int bufsize) { - static pid_t pid= (pid_t)-1; - int outsize = 0; - extern uint16 global_smbpid; + static pid_t pid= (pid_t)-1; + int outsize = 0; + extern uint16 global_smbpid; - type &= 0xff; + type &= 0xff; - if (pid == (pid_t)-1) - pid = sys_getpid(); + if (pid == (pid_t)-1) + pid = sys_getpid(); - errno = 0; - last_message = type; + errno = 0; + last_message = type; - /* Make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */ - if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size - 4))) { - DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf))); - exit_server("Non-SMB packet"); - return(-1); - } + /* make sure this is an SMB packet. smb_size contains NetBIOS header so subtract 4 from it. */ + if ((strncmp(smb_base(inbuf),"\377SMB",4) != 0) || (size < (smb_size-4))) { + DEBUG(0,("Non-SMB packet of length %d. Terminating server\n",smb_len(inbuf))); + exit_server("Non-SMB packet"); + return(-1); + } - /* yuck! this is an interim measure before we get rid of our - current inbuf/outbuf system */ - global_smbpid = SVAL(inbuf,smb_pid); - - if (smb_messages[type].fn == NULL) { - DEBUG(0,("Unknown message type %d!\n",type)); - smb_dump("Unknown", 1, inbuf, size); - outsize = reply_unknown(inbuf,outbuf); - } else { - int flags = smb_messages[type].flags; - static uint16 last_session_tag = UID_FIELD_INVALID; - /* In share mode security we must ignore the vuid. */ - uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); - connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - - DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); - - smb_dump(smb_fn_name(type), 1, inbuf, size); - if(global_oplock_break) { - if(flags & QUEUE_IN_OPLOCK) { - /* - * Queue this message as we are the process of an oplock break. - */ - - DEBUG( 2, ( "switch_message: queueing message due to being in " ) ); - DEBUGADD( 2, ( "oplock break state.\n" ) ); - - push_oplock_pending_smb_message( inbuf, size ); - return -1; - } - } + /* yuck! this is an interim measure before we get rid of our + current inbuf/outbuf system */ + global_smbpid = SVAL(inbuf,smb_pid); - /* Ensure this value is replaced in the incoming packet. */ - SSVAL(inbuf,smb_uid,session_tag); + if (smb_messages[type].fn == NULL) + { + DEBUG(0,("Unknown message type %d!\n",type)); + smb_dump("Unknown", 1, inbuf, size); + outsize = reply_unknown(inbuf,outbuf); + } + else + { + int flags = smb_messages[type].flags; + static uint16 last_session_tag = UID_FIELD_INVALID; + /* In share mode security we must ignore the vuid. */ + uint16 session_tag = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(inbuf,smb_uid); + connection_struct *conn = conn_find(SVAL(inbuf,smb_tid)); - /* - * Ensure the correct username is in current_user_info. - * This is a really ugly bugfix for problems with - * multiple session_setup_and_X's being done and - * allowing %U and %G substitutions to work correctly. - * There is a reason this code is done here, don't - * move it unless you know what you're doing... :-). - * JRA. - */ + DEBUG(3,("switch message %s (pid %d)\n",smb_fn_name(type),(int)pid)); - if (session_tag != last_session_tag) { - user_struct *vuser = NULL; + smb_dump(smb_fn_name(type), 1, inbuf, size); + if(global_oplock_break) + { + if(flags & QUEUE_IN_OPLOCK) + { + /* + * Queue this message as we are the process of an oplock break. + */ + + DEBUG( 2, ( "switch_message: queueing message due to being in " ) ); + DEBUGADD( 2, ( "oplock break state.\n" ) ); + + push_oplock_pending_smb_message( inbuf, size ); + return -1; + } + } - last_session_tag = session_tag; - if(session_tag != UID_FIELD_INVALID) - vuser = get_valid_user_struct(session_tag); - if(vuser != NULL) - current_user_info = vuser->user; - } + /* Ensure this value is replaced in the incoming packet. */ + SSVAL(inbuf,smb_uid,session_tag); - /* does this protocol need to be run as root? */ - if (!(flags & AS_USER)) - change_to_root_user(); + /* + * Ensure the correct username is in current_user_info. + * This is a really ugly bugfix for problems with + * multiple session_setup_and_X's being done and + * allowing %U and %G substitutions to work correctly. + * There is a reason this code is done here, don't + * move it unless you know what you're doing... :-). + * JRA. + */ - /* does this protocol need a valid tree connection? */ - if ((flags & AS_USER) && !conn) - return ERROR_DOS(ERRSRV, ERRinvnid); + if (session_tag != last_session_tag) { + user_struct *vuser = NULL; + last_session_tag = session_tag; + if(session_tag != UID_FIELD_INVALID) + vuser = get_valid_user_struct(session_tag); + if(vuser != NULL) + current_user_info = vuser->user; + } - /* does this protocol need to be run as the connected user? */ - if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { - if (flags & AS_GUEST) - flags &= ~AS_USER; - else - return(ERROR_DOS(ERRSRV,ERRaccess)); - } + /* does this protocol need to be run as root? */ + if (!(flags & AS_USER)) + change_to_root_user(); - /* this code is to work around a bug is MS client 3 without - introducing a security hole - it needs to be able to do - print queue checks as guest if it isn't logged in properly */ - if (flags & AS_USER) - flags &= ~AS_GUEST; + /* does this protocol need a valid tree connection? */ + if ((flags & AS_USER) && !conn) { + return ERROR_DOS(ERRSRV, ERRinvnid); + } - /* does it need write permission? */ - if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) - return(ERROR_DOS(ERRSRV,ERRaccess)); - /* ipc services are limited */ - if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) - return(ERROR_DOS(ERRSRV,ERRaccess)); + /* does this protocol need to be run as the connected user? */ + if ((flags & AS_USER) && !change_to_user(conn,session_tag)) { + if (flags & AS_GUEST) + flags &= ~AS_USER; + else + return(ERROR_DOS(ERRSRV,ERRaccess)); + } - /* load service specific parameters */ - if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) - return(ERROR_DOS(ERRSRV,ERRaccess)); + /* this code is to work around a bug is MS client 3 without + introducing a security hole - it needs to be able to do + print queue checks as guest if it isn't logged in properly */ + if (flags & AS_USER) + flags &= ~AS_GUEST; - /* does this protocol need to be run as guest? */ - if ((flags & AS_GUEST) && (!change_to_guest() || - !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) - return(ERROR_DOS(ERRSRV,ERRaccess)); + /* does it need write permission? */ + if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) + return(ERROR_DOS(ERRSRV,ERRaccess)); - last_inbuf = inbuf; + /* ipc services are limited */ + if (IS_IPC(conn) && (flags & AS_USER) && !(flags & CAN_IPC)) { + return(ERROR_DOS(ERRSRV,ERRaccess)); + } - outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize); - } + /* load service specific parameters */ + if (conn && !set_current_service(conn,(flags & AS_USER)?True:False)) { + return(ERROR_DOS(ERRSRV,ERRaccess)); + } - smb_dump(smb_fn_name(type), 0, outbuf, outsize); + /* does this protocol need to be run as guest? */ + if ((flags & AS_GUEST) && + (!change_to_guest() || + !check_access(smbd_server_fd(), lp_hostsallow(-1), lp_hostsdeny(-1)))) { + return(ERROR_DOS(ERRSRV,ERRaccess)); + } - return(outsize); + last_inbuf = inbuf; + + outsize = smb_messages[type].fn(conn, inbuf,outbuf,size,bufsize); + } + + smb_dump(smb_fn_name(type), 0, outbuf, outsize); + + return(outsize); } /**************************************************************************** - Construct a reply to the incoming packet. + construct a reply to the incoming packet ****************************************************************************/ - static int construct_reply(char *inbuf,char *outbuf,int size,int bufsize) { - int type = CVAL(inbuf,smb_com); - int outsize = 0; - int msg_type = CVAL(inbuf,0); + int type = CVAL(inbuf,smb_com); + int outsize = 0; + int msg_type = CVAL(inbuf,0); - GetTimeOfDay(&smb_last_time); + GetTimeOfDay(&smb_last_time); - chain_size = 0; - file_chain_reset(); - reset_chain_p(); + chain_size = 0; + file_chain_reset(); + reset_chain_p(); - if (msg_type != 0) - return(reply_special(inbuf,outbuf)); + if (msg_type != 0) + return(reply_special(inbuf,outbuf)); - construct_reply_common(inbuf, outbuf); + construct_reply_common(inbuf, outbuf); - outsize = switch_message(type,inbuf,outbuf,size,bufsize); + outsize = switch_message(type,inbuf,outbuf,size,bufsize); - outsize += chain_size; + outsize += chain_size; - if(outsize > 4) - smb_setlen(outbuf,outsize - 4); - return(outsize); + if(outsize > 4) + smb_setlen(outbuf,outsize - 4); + return(outsize); } /**************************************************************************** - Keep track of the number of running smbd's. This functionality is used to - 'hard' limit Samba overhead on resource constrained systems. + Keep track of the number of running smbd's. This functionality is used to + 'hard' limit Samba overhead on resource constrained systems. ****************************************************************************/ - static BOOL smbd_process_limit(void) { int32 total_smbds; @@ -829,11 +841,15 @@ set. Ignoring max smbd restriction.\n")); } /**************************************************************************** - process an smb from the client - split out from the smbd_process() code so + process an smb from the client - split out from the process() code so it can be used by the oplock break code. ****************************************************************************/ void process_smb(char *inbuf, char *outbuf) { +#ifdef WITH_SSL + extern BOOL sslEnabled; /* don't use function for performance reasons */ + static int sslConnected = 0; +#endif /* WITH_SSL */ static int trans_num; int msg_type = CVAL(inbuf,0); int32 len = smb_len(inbuf); @@ -861,9 +877,21 @@ void process_smb(char *inbuf, char *outbuf) DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type, len ) ); DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, nread ) ); +#ifdef WITH_SSL + if(sslEnabled && !sslConnected){ + sslConnected = sslutil_negotiate_ssl(smbd_server_fd(), msg_type); + if(sslConnected < 0){ /* an error occured */ + exit_server("SSL negotiation failed"); + }else if(sslConnected){ + trans_num++; + return; + } + } +#endif /* WITH_SSL */ + if (msg_type == 0) show_msg(inbuf); - else if(msg_type == SMBkeepalive) + else if(msg_type == 0x85) return; /* Keepalive packet. */ nread = construct_reply(inbuf,outbuf,nread,max_send); @@ -880,7 +908,7 @@ void process_smb(char *inbuf, char *outbuf) } else if (!send_smb(smbd_server_fd(),outbuf)) - exit_server("process_smb: send_smb failed."); + exit_server("process_smb: send_smb failed.\n"); } trans_num++; } @@ -890,7 +918,7 @@ void process_smb(char *inbuf, char *outbuf) /**************************************************************************** return a string containing the function name of a SMB command ****************************************************************************/ -const char *smb_fn_name(int type) +char *smb_fn_name(int type) { static char *unknown_name = "SMBunknown"; @@ -907,25 +935,24 @@ const char *smb_fn_name(int type) void construct_reply_common(char *inbuf,char *outbuf) { - memset(outbuf,'\0',smb_size); - - set_message(outbuf,0,0,True); - SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); - - memcpy(outbuf+4,inbuf+4,4); - SCVAL(outbuf,smb_rcls,SMB_SUCCESS); - SCVAL(outbuf,smb_reh,0); - SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); - SSVAL(outbuf,smb_flg2, - (SVAL(inbuf,smb_flg2) & FLAGS2_UNICODE_STRINGS) | - FLAGS2_LONG_PATH_COMPONENTS | - FLAGS2_32_BIT_ERROR_CODES | FLAGS2_EXTENDED_SECURITY); - - SSVAL(outbuf,smb_err,SMB_SUCCESS); - SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); - SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); - SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid)); - SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid)); + memset(outbuf,'\0',smb_size); + + set_message(outbuf,0,0,True); + SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com)); + + memcpy(outbuf+4,inbuf+4,4); + SCVAL(outbuf,smb_rcls,SMB_SUCCESS); + SCVAL(outbuf,smb_reh,0); + SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); /* bit 7 set + means a reply */ + SSVAL(outbuf,smb_flg2,FLAGS2_LONG_PATH_COMPONENTS); + /* say we support long filenames */ + + SSVAL(outbuf,smb_err,SMB_SUCCESS); + SSVAL(outbuf,smb_tid,SVAL(inbuf,smb_tid)); + SSVAL(outbuf,smb_pid,SVAL(inbuf,smb_pid)); + SSVAL(outbuf,smb_uid,SVAL(inbuf,smb_uid)); + SSVAL(outbuf,smb_mid,SVAL(inbuf,smb_mid)); } /**************************************************************************** @@ -1030,11 +1057,7 @@ static int setup_select_timeout(void) select_timeout *= 1000; t = change_notify_timeout(); - if (t != -1) - select_timeout = MIN(select_timeout, t*1000); - - if (print_notify_messages_pending()) - select_timeout = MIN(select_timeout, 1000); + if (t != -1) select_timeout = MIN(select_timeout, t*1000); return select_timeout; } @@ -1053,7 +1076,7 @@ void check_reload(int t) if (reload_after_sighup || (t >= last_smb_conf_reload_time+SMBD_RELOAD_CHECK)) { reload_services(True); - reload_after_sighup = False; + reload_after_sighup = 0; last_smb_conf_reload_time = t; } } @@ -1108,23 +1131,19 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t if (keepalive && (t - last_keepalive_sent_time)>keepalive) { - extern struct auth_context *negprot_global_auth_context; - if (!send_keepalive(smbd_server_fd())) { - DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); - return False; - } - - /* send a keepalive for a password server or the like. - This is attached to the auth_info created in the - negprot */ - if (negprot_global_auth_context - && negprot_global_auth_context->challenge_set_method - && negprot_global_auth_context->challenge_set_method->send_keepalive) { - negprot_global_auth_context->challenge_set_method->send_keepalive - (&negprot_global_auth_context->challenge_set_method->private_data); - } - - last_keepalive_sent_time = t; + struct cli_state *cli = server_client(); + if (!send_keepalive(smbd_server_fd())) { + DEBUG( 2, ( "Keepalive failed - exiting.\n" ) ); + return False; + } + /* also send a keepalive to the password server if its still + connected */ + if (cli && cli->initialised) + if (!send_keepalive(cli->fd)) { + DEBUG( 2, ( "password server keepalive failed.\n")); + cli_shutdown(cli); + } + last_keepalive_sent_time = t; } /* check for connection timeouts */ @@ -1135,10 +1154,7 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t return False; } - if(global_machine_password_needs_changing && - /* for ADS we need to do a regular ADS password change, not a domain - password change */ - lp_security() == SEC_DOMAIN) + if(global_machine_password_needs_changing && lp_security() == SEC_DOMAIN) { unsigned char trust_passwd_hash[16]; time_t lct; @@ -1154,16 +1170,9 @@ static BOOL timeout_processing(int deadtime, int *select_timeout, time_t *last_t * First, open the machine password file with an exclusive lock. */ - if (secrets_lock_trust_account_password(global_myworkgroup, True) == False) { - DEBUG(0,("process: unable to lock the machine account password for \ -machine %s in domain %s.\n", global_myname, global_myworkgroup )); - return True; - } - if(!secrets_fetch_trust_account_password(global_myworkgroup, trust_passwd_hash, &lct)) { DEBUG(0,("process: unable to read the machine account password for \ machine %s in domain %s.\n", global_myname, global_myworkgroup )); - secrets_lock_trust_account_password(global_myworkgroup, False); return True; } @@ -1173,7 +1182,6 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); if(t < lct + lp_machine_password_timeout()) { global_machine_password_needs_changing = False; - secrets_lock_trust_account_password(global_myworkgroup, False); return True; } @@ -1181,7 +1189,6 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); change_trust_account_password( global_myworkgroup, remote_machine_list); global_machine_password_needs_changing = False; - secrets_lock_trust_account_password(global_myworkgroup, False); } /* @@ -1203,10 +1210,6 @@ machine %s in domain %s.\n", global_myname, global_myworkgroup )); force_check_log_size(); check_log_size(); - /* Send any queued printer notify message to interested smbd's. */ - - print_notify_send_messages(); - /* * Modify the select timeout depending upon * what we have remaining in our queues. @@ -1232,8 +1235,17 @@ void smbd_process(void) if ((InBuffer == NULL) || (OutBuffer == NULL)) return; + InBuffer += SMB_ALIGNMENT; + OutBuffer += SMB_ALIGNMENT; + max_recv = MIN(lp_maxxmit(),BUFFER_SIZE); + /* re-initialise the timezone */ + TimeInit(); + + /* register our message handlers */ + message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis); + while (True) { int deadtime = lp_deadtime()*60; int select_timeout = setup_select_timeout(); |