X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source%2Flib%2Futil.c;h=8d1f61931890fc54965d7ffdd7704ae8cc16dab7;hb=3bda7ac417107a7b01d91805ca71c4330657ed21;hp=05dd6198135ac4463b86ff3db504393c506a1bd6;hpb=7e3d4c8b21f63a06d32605d230129e36883ad08c;p=samba.git diff --git a/source/lib/util.c b/source/lib/util.c index 05dd6198135..8d1f6193189 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Samba utility functions - Copyright (C) Andrew Tridgell 1992-1997 + Copyright (C) Andrew Tridgell 1992-1998 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 @@ -21,6 +21,21 @@ #include "includes.h" +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) +#ifdef NISPLUS_HOME +#include +#else +#include "rpcsvc/ypclnt.h" +#endif +#endif + +#ifdef WITH_SSL +#include +#undef Realloc /* SSLeay defines this and samba has a function of this name */ +extern SSL *ssl; +extern int sslFd; +#endif /* WITH_SSL */ + pstring scope = ""; int DEBUGLEVEL = 1; @@ -55,7 +70,7 @@ int trans_num = 0; int case_default = CASE_LOWER; pstring debugf = ""; -int syslog_level; +int syslog_level = 0; /* the following control case operations - they are put here so the client can link easily */ @@ -72,9 +87,14 @@ static enum remote_arch_types ra_type = RA_UNKNOWN; fstring remote_proto="UNKNOWN"; pstring myhostname=""; pstring user_socket_options=""; + pstring sesssetup_user=""; -pstring myname = ""; -fstring myworkgroup = ""; +pstring samlogon_user=""; + +BOOL sam_logon_in_ssb = False; + +pstring global_myname = ""; +fstring global_myworkgroup = ""; char **my_netbios_names; int smb_read_error = 0; @@ -83,20 +103,64 @@ static BOOL stdout_logging = False; static char *filename_dos(char *path,char *buf); +#if defined(SIGUSR2) +/****************************************************************************** + catch a sigusr2 - decrease the debug log level. + *****************************************************************************/ +int sig_usr2(void) +{ + BlockSignals( True, SIGUSR2); + + DEBUGLEVEL--; + + if(DEBUGLEVEL < 0) + DEBUGLEVEL = 0; + + DEBUG( 0, ( "Got SIGUSR2 set debug level to %d.\n", DEBUGLEVEL ) ); + + BlockSignals( False, SIGUSR2); + CatchSignal(SIGUSR2, SIGNAL_CAST sig_usr2); + + return(0); +} +#endif /* SIGUSR1 */ + +#if defined(SIGUSR1) +/****************************************************************************** + catch a sigusr1 - increase the debug log level. + *****************************************************************************/ +int sig_usr1(void) +{ + BlockSignals( True, SIGUSR1); + + DEBUGLEVEL++; + + if(DEBUGLEVEL > 10) + DEBUGLEVEL = 10; + + DEBUG( 0, ( "Got SIGUSR1 set debug level to %d.\n", DEBUGLEVEL ) ); + + BlockSignals( False, SIGUSR1); + CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1); + return(0); +} +#endif /* SIGUSR1 */ + + /******************************************************************* get ready for syslog stuff ******************************************************************/ void setup_logging(char *pname,BOOL interactive) { -#ifdef SYSLOG +#ifdef WITH_SYSLOG if (!interactive) { char *p = strrchr(pname,'/'); if (p) pname = p+1; #ifdef LOG_DAEMON - openlog(pname, LOG_PID, LOG_DAEMON); -#else /* LOG_DAEMON - for old systems that have no facility codes. */ + openlog(pname, LOG_PID, SYSLOG_FACILITY); +#else /* for old systems that have no facility codes. */ openlog(pname, LOG_PID); -#endif /* LOG_DAEMON */ +#endif } #endif if (interactive) { @@ -114,61 +178,87 @@ reopen the log files ****************************************************************************/ void reopen_logs(void) { - extern FILE *dbf; pstring fname; if (DEBUGLEVEL > 0) - { - strcpy(fname,debugf); - if (lp_loaded() && (*lp_logfile())) - strcpy(fname,lp_logfile()); + { + pstrcpy(fname,debugf); + if (lp_loaded() && (*lp_logfile())) + pstrcpy(fname,lp_logfile()); - if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) - { - int oldumask = umask(022); - strcpy(debugf,fname); - if (dbf) fclose(dbf); - if (append_log) - dbf = fopen(debugf,"a"); - else - dbf = fopen(debugf,"w"); - if (dbf) setbuf(dbf,NULL); - umask(oldumask); - } + if (!strcsequal(fname,debugf) || !dbf || !file_exist(debugf,NULL)) + { + int oldumask = umask(022); + pstrcpy(debugf,fname); + if (dbf) + fclose(dbf); + if (append_log) + dbf = fopen(debugf,"a"); + else + dbf = fopen(debugf,"w"); + /* + * Fix from klausr@ITAP.Physik.Uni-Stuttgart.De + * to fix problem where smbd's that generate less + * than 100 messages keep growing the log. + */ + force_check_log_size(); + if (dbf) + setbuf(dbf,NULL); + umask(oldumask); } + } else + { + if (dbf) { - if (dbf) - { - fclose(dbf); - dbf = NULL; - } + fclose(dbf); + dbf = NULL; } + } } +/******************************************************************* + Number of debug messages that have been output. + Used to check log size. +********************************************************************/ + +static int debug_count=0; + +/******************************************************************* + Force a check of the log size. +********************************************************************/ + +void force_check_log_size(void) +{ + debug_count = 100; +} /******************************************************************* -check if the log has grown too big + Check if the log has grown too big ********************************************************************/ + static void check_log_size(void) { - static int debug_count=0; int maxlog; struct stat st; - if (debug_count++ < 100) return; + if (debug_count++ < 100 || getuid() != 0) + return; maxlog = lp_max_log_size() * 1024; - if (!dbf || maxlog <= 0) return; + if (!dbf || maxlog <= 0) + return; if (fstat(fileno(dbf),&st) == 0 && st.st_size > maxlog) { - fclose(dbf); dbf = NULL; + fclose(dbf); + dbf = NULL; reopen_logs(); if (dbf && file_size(debugf) > maxlog) { pstring name; - fclose(dbf); dbf = NULL; - sprintf(name,"%s.old",debugf); - sys_rename(debugf,name); + fclose(dbf); + dbf = NULL; + slprintf(name,sizeof(name)-1,"%s.old",debugf); + rename(debugf,name); reopen_logs(); } } @@ -180,7 +270,7 @@ static void check_log_size(void) write an debug message on the debugfile. This is called by the DEBUG macro ********************************************************************/ -#ifdef __STDC__ +#ifdef HAVE_STDARG_H int Debug1(char *format_str, ...) { #else @@ -190,9 +280,10 @@ va_dcl char *format_str; #endif va_list ap; - + int old_errno = errno; + if (stdout_logging) { -#ifdef __STDC__ +#ifdef HAVE_STDARG_H va_start(ap, format_str); #else va_start(ap); @@ -200,26 +291,31 @@ va_dcl #endif vfprintf(dbf,format_str,ap); va_end(ap); + errno = old_errno; return(0); } -#ifdef SYSLOG +#ifdef WITH_SYSLOG if (!lp_syslog_only()) #endif { - if (!dbf) - { - int oldumask = umask(022); - dbf = fopen(debugf,"w"); - umask(oldumask); - if (dbf) - setbuf(dbf,NULL); - else - return(0); - } + if (!dbf) { + int oldumask = umask(022); + if(append_log) + dbf = fopen(debugf,"a"); + else + dbf = fopen(debugf,"w"); + umask(oldumask); + if (dbf) { + setbuf(dbf,NULL); + } else { + errno = old_errno; + return(0); + } + } } -#ifdef SYSLOG +#ifdef WITH_SYSLOG if (syslog_level < lp_syslog()) { /* @@ -242,13 +338,13 @@ va_dcl else priority = priority_map[syslog_level]; -#ifdef __STDC__ +#ifdef HAVE_STDARG_H va_start(ap, format_str); #else va_start(ap); format_str = va_arg(ap,char *); #endif - vsprintf(msgbuf, format_str, ap); + vslprintf(msgbuf, sizeof(msgbuf)-1,format_str, ap); va_end(ap); msgbuf[255] = '\0'; @@ -256,11 +352,11 @@ va_dcl } #endif -#ifdef SYSLOG +#ifdef WITH_SYSLOG if (!lp_syslog_only()) #endif { -#ifdef __STDC__ +#ifdef HAVE_STDARG_H va_start(ap, format_str); #else va_start(ap); @@ -273,6 +369,8 @@ va_dcl check_log_size(); + errno = old_errno; + return(0); } @@ -382,66 +480,20 @@ char **toktocliplist(int *ctok, char *sep) return ret; } -#ifndef HAVE_MEMMOVE -/******************************************************************* -safely copies memory, ensuring no overlap problems. -this is only used if the machine does not have it's own memmove(). -this is not the fastest algorithm in town, but it will do for our -needs. -********************************************************************/ -void *MemMove(void *dest,void *src,int size) -{ - unsigned long d,s; - int i; - if (dest==src || !size) return(dest); - - d = (unsigned long)dest; - s = (unsigned long)src; - - if ((d >= (s+size)) || (s >= (d+size))) { - /* no overlap */ - memcpy(dest,src,size); - return(dest); - } - if (d < s) - { - /* we can forward copy */ - if (s-d >= sizeof(int) && - !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { - /* do it all as words */ - int *idest = (int *)dest; - int *isrc = (int *)src; - size /= sizeof(int); - for (i=0;i= sizeof(int) && - !(s%sizeof(int)) && !(d%sizeof(int)) && !(size%sizeof(int))) { - /* do it all as words */ - int *idest = (int *)dest; - int *isrc = (int *)src; - size /= sizeof(int); - for (i=size-1;i>=0;i--) idest[i] = isrc[i]; - } else { - /* simplest */ - char *cdest = (char *)dest; - char *csrc = (char *)src; - for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; - } - } - return(dest); -} -#endif +/* ************************************************************************* ** + * Duplicate a block of memory. + * ************************************************************************* ** + */ +void *mem_dup( void *from, int size ) + { + void *tmp; + tmp = malloc( size ); + if( NULL != tmp ) + (void)memcpy( tmp, from, size ); + return( tmp ); + } /* mem_dup */ /**************************************************************************** prompte a dptr (to make it recently used) @@ -514,7 +566,7 @@ set user socket options ****************************************************************************/ void set_socket_options(int fd, char *options) { - string tok; + fstring tok; while (next_token(&options,tok," \t,")) { @@ -572,6 +624,10 @@ void set_socket_options(int fd, char *options) ****************************************************************************/ void close_sockets(void ) { +#ifdef WITH_SSL + sslutil_disconnect(Client); +#endif /* WITH_SSL */ + close(Client); Client = 0; } @@ -684,48 +740,61 @@ static int name_interpret(char *in,char *out) /**************************************************************************** mangle a name into netbios format + + Note: must be (33 + strlen(scope) + 2) bytes long, at minimum. ****************************************************************************/ -int name_mangle(char *In,char *Out,char name_type) -{ - fstring name; - char buf[20]; - char *in = (char *)&buf[0]; - char *out = (char *)Out; - char *p, *label; - int i; +int name_mangle( char *In, char *Out, char name_type ) + { + int i; + int c; + int len; + char buf[20]; + char *p = Out; + + /* Safely copy the input string, In, into buf[]. */ + (void)memset( buf, 0, 20 ); + if( '*' == In[0] ) + buf[0] = '*'; + else + (void)slprintf( buf, sizeof(buf) - 1, "%-15.15s%c", In, name_type ); - if (In[0] != '*') { - StrnCpy(name,In,sizeof(name)-1); - sprintf(buf,"%-15.15s%c",name,name_type); - } else { - buf[0]='*'; - memset(&buf[1],0,16); - } + /* Place the length of the first field into the output buffer. */ + p[0] = 32; + p++; - *out++ = 32; - for (i=0;i<16;i++) { - char c = toupper(in[i]); - out[i*2] = (c>>4) + 'A'; - out[i*2+1] = (c & 0xF) + 'A'; - } - out[32]=0; - out += 32; - - label = scope; - while (*label) + /* Now convert the name to the rfc1001/1002 format. */ + for( i = 0; i < 16; i++ ) { - p = strchr(label, '.'); - if (p == 0) - p = label + strlen(label); - *out++ = p - label; - memcpy(out, label, p - label); - out += p - label; - label += p - label + (*p == '.'); + c = toupper( buf[i] ); + p[i*2] = ( (c >> 4) & 0x000F ) + 'A'; + p[(i*2)+1] = (c & 0x000F) + 'A'; + } + p += 32; + p[0] = '\0'; + + /* Add the scope string. */ + for( i = 0, len = 0; NULL != scope; i++, len++ ) + { + switch( scope[i] ) + { + case '\0': + p[0] = len; + if( len > 0 ) + p[len+1] = 0; + return( name_len(Out) ); + case '.': + p[0] = len; + p += (len + 1); + len = 0; + break; + default: + p[len+1] = scope[i]; + break; + } } - *out = 0; - return(name_len(Out)); -} + return( name_len(Out) ); + } /* name_mangle */ /******************************************************************* check if a file exists @@ -789,16 +858,16 @@ return a string representing an attribute for a file ********************************************************************/ char *attrib_string(int mode) { - static char attrstr[10]; + static fstring attrstr; attrstr[0] = 0; - if (mode & aVOLID) strcat(attrstr,"V"); - if (mode & aDIR) strcat(attrstr,"D"); - if (mode & aARCH) strcat(attrstr,"A"); - if (mode & aHIDDEN) strcat(attrstr,"H"); - if (mode & aSYSTEM) strcat(attrstr,"S"); - if (mode & aRONLY) strcat(attrstr,"R"); + if (mode & aVOLID) fstrcat(attrstr,"V"); + if (mode & aDIR) fstrcat(attrstr,"D"); + if (mode & aARCH) fstrcat(attrstr,"A"); + if (mode & aHIDDEN) fstrcat(attrstr,"H"); + if (mode & aSYSTEM) fstrcat(attrstr,"S"); + if (mode & aRONLY) fstrcat(attrstr,"R"); return(attrstr); } @@ -814,6 +883,15 @@ int StrCaseCmp(char *s, char *t) asynchronous upper to lower mapping. */ #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -878,6 +956,15 @@ int StrnCaseCmp(char *s, char *t, int n) asynchronous upper to lower mapping. */ #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -926,10 +1013,11 @@ int StrnCaseCmp(char *s, char *t, int n) else #endif /* KANJI_WIN95_COMPATIBILITY */ { - while (n-- && *s && *t && toupper(*s) == toupper(*t)) + while (n && *s && *t && toupper(*s) == toupper(*t)) { s++; t++; + n--; } /* not run out of chars - strings are different lengths */ @@ -984,6 +1072,15 @@ void strlower(char *s) while (*s) { #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -1007,9 +1104,15 @@ void strlower(char *s) else #endif /* KANJI_WIN95_COMPATIBILITY */ { - if (isupper(*s)) - *s = tolower(*s); - s++; + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (isupper(*s)) + *s = tolower(*s); + s++; + } } } } @@ -1022,6 +1125,15 @@ void strupper(char *s) while (*s) { #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -1045,9 +1157,15 @@ void strupper(char *s) else #endif /* KANJI_WIN95_COMPATIBILITY */ { - if (islower(*s)) - *s = toupper(*s); - s++; + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else + { + if (islower(*s)) + *s = toupper(*s); + s++; + } } } } @@ -1080,25 +1198,13 @@ BOOL strisnormal(char *s) ****************************************************************************/ void string_replace(char *s,char oldc,char newc) { + int skip; while (*s) { -#if !defined(KANJI_WIN95_COMPATIBILITY) - if(lp_client_code_page() == KANJI_CODEPAGE) - { - /* Win95 treats full width ascii characters as case sensitive. */ - if (is_shift_jis (*s)) - s += 2; - else if (is_kana (*s)) - s++; - else - { - if (oldc == *s) - *s = newc; - s++; - } - } + skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; else -#endif /* KANJI_WIN95_COMPATIBILITY */ { if (oldc == *s) *s = newc; @@ -1118,8 +1224,8 @@ void unix_format(char *fname) if (*fname == '/') { pstrcpy(namecopy,fname); - strcpy(fname,"."); - strcat(fname,namecopy); + pstrcpy(fname,"."); + pstrcat(fname,namecopy); } } @@ -1131,63 +1237,50 @@ void dos_format(char *fname) string_replace(fname,'/','\\'); } - /******************************************************************* show a smb message structure ********************************************************************/ void show_msg(char *buf) { - int i; - int j; - int bcc=0; - if (DEBUGLEVEL < 5) - return; - - DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", - smb_len(buf), - (int)CVAL(buf,smb_com), - (int)CVAL(buf,smb_rcls), - (int)CVAL(buf,smb_reh), - (int)SVAL(buf,smb_err), - (int)CVAL(buf,smb_flg), - (int)SVAL(buf,smb_flg2))); - DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", - (int)SVAL(buf,smb_tid), - (int)SVAL(buf,smb_pid), - (int)SVAL(buf,smb_uid), - (int)SVAL(buf,smb_mid), - (int)CVAL(buf,smb_wct))); - for (i=0;i<(int)CVAL(buf,smb_wct);i++) - DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, - SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); - bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); - DEBUG(5,("smb_bcc=%d\n",bcc)); - if (DEBUGLEVEL < 10) - return; - for (i = 0; i < MIN(bcc, 256); i += 16) - { - for (j = 0; j < 16 && i+j < MIN(bcc,256); j++) - { + int i; + int bcc=0; + + if (DEBUGLEVEL < 5) return; + + DEBUG(5,("size=%d\nsmb_com=0x%x\nsmb_rcls=%d\nsmb_reh=%d\nsmb_err=%d\nsmb_flg=%d\nsmb_flg2=%d\n", + smb_len(buf), + (int)CVAL(buf,smb_com), + (int)CVAL(buf,smb_rcls), + (int)CVAL(buf,smb_reh), + (int)SVAL(buf,smb_err), + (int)CVAL(buf,smb_flg), + (int)SVAL(buf,smb_flg2))); + DEBUG(5,("smb_tid=%d\nsmb_pid=%d\nsmb_uid=%d\nsmb_mid=%d\nsmt_wct=%d\n", + (int)SVAL(buf,smb_tid), + (int)SVAL(buf,smb_pid), + (int)SVAL(buf,smb_uid), + (int)SVAL(buf,smb_mid), + (int)CVAL(buf,smb_wct))); + + for (i=0;i<(int)CVAL(buf,smb_wct);i++) + { + DEBUG(5,("smb_vwv[%d]=%d (0x%X)\n",i, + SVAL(buf,smb_vwv+2*i),SVAL(buf,smb_vwv+2*i))); + } - DEBUG(10,("%2X ",CVAL(smb_buf(buf),i+j))); - if (j == 7) DEBUG(10, (" ")); + bcc = (int)SVAL(buf,smb_vwv+2*(CVAL(buf,smb_wct))); - } - DEBUG(10,(" ")); + DEBUG(5,("smb_bcc=%d\n",bcc)); - for (j = 0; j < 16 && i+j < MIN(bcc,256); j++) - { - unsigned char c = CVAL(smb_buf(buf),i+j); - if (c < 32 || c > 128) c = '.'; - DEBUG(10,("%c",c)); + if (DEBUGLEVEL < 10) return; - if (j == 7) DEBUG(10, (" ")); - } + if (DEBUGLEVEL < 50) + { + bcc = MIN(bcc, 512); + } - DEBUG(10,("\n")); -} + dump_data(10, smb_buf(buf), bcc); } - /******************************************************************* return the length of an smb packet ********************************************************************/ @@ -1334,7 +1427,7 @@ void dos_clean_name(char *s) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"\\.."); @@ -1358,7 +1451,7 @@ void unix_clean_name(char *s) if(strncmp(s, "./", 2) == 0) { trim_string(s, "./", NULL); if(*s == 0) - strcpy(s,"./"); + pstrcpy(s,"./"); } while ((p = strstr(s,"/../")) != NULL) @@ -1372,7 +1465,7 @@ void unix_clean_name(char *s) *p = 0; else *s = 0; - strcat(s,s1); + pstrcat(s,s1); } trim_string(s,NULL,"/.."); @@ -1465,7 +1558,7 @@ char *GetWd(char *str) st.st_dev == st2.st_dev && (st2.st_mode & S_IFMT) == S_IFDIR) { - strcpy (str, ino_list[i].text); + pstrcpy (str, ino_list[i].text); /* promote it for future use */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); @@ -1492,7 +1585,7 @@ char *GetWd(char *str) return (NULL); } - strcpy(str,s); + pstrcpy(str,s); DEBUG(5,("GetWd %s, inode %d, dev %x\n",s,(int)st.st_ino,(int)st.st_dev)); @@ -1525,12 +1618,12 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) #else pstring dir2; pstring wd; - pstring basename; + pstring base_name; pstring newname; char *p=NULL; BOOL relative = (*s != '/'); - *dir2 = *wd = *basename = *newname = 0; + *dir2 = *wd = *base_name = *newname = 0; if (widelinks) { @@ -1543,7 +1636,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) } if (strlen(s) == 0) - strcpy(s,"./"); + pstrcpy(s,"./"); return(True); } @@ -1553,8 +1646,8 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) /* remove any double slashes */ string_sub(s,"//","/"); - pstrcpy(basename,s); - p = strrchr(basename,'/'); + pstrcpy(base_name,s); + p = strrchr(base_name,'/'); if (!p) return(True); @@ -1579,7 +1672,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) } - if (p && (p != basename)) + if (p && (p != base_name)) { *p = 0; if (strcmp(p+1,".")==0) @@ -1588,10 +1681,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) *p = '/'; } - if (ChDir(basename) != 0) + if (ChDir(base_name) != 0) { ChDir(wd); - DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,basename)); + DEBUG(3,("couldn't chdir for %s %s basename=%s\n",s,dir,base_name)); return(False); } @@ -1602,10 +1695,10 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) return(False); } - if (p && (p != basename)) + if (p && (p != base_name)) { - strcat(newname,"/"); - strcat(newname,p+1); + pstrcat(newname,"/"); + pstrcat(newname,p+1); } { @@ -1634,7 +1727,7 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks) ChDir(wd); if (strlen(s) == 0) - strcpy(s,"./"); + pstrcpy(s,"./"); DEBUG(3,("reduced to %s\n",s)); return(True); @@ -1689,7 +1782,7 @@ void expand_mask(char *Mask,BOOL doext) } else { - strcpy(mext,""); + pstrcpy(mext,""); if (strlen(mbeg) > 8) { pstrcpy(mext,mbeg + 8); @@ -1698,12 +1791,12 @@ void expand_mask(char *Mask,BOOL doext) } if (*mbeg == 0) - strcpy(mbeg,"????????"); + pstrcpy(mbeg,"????????"); if ((*mext == 0) && doext && !hasdot) - strcpy(mext,"???"); + pstrcpy(mext,"???"); if (strequal(mbeg,"*") && *mext==0) - strcpy(mext,"*"); + pstrcpy(mext,"*"); /* expand *'s */ expand_one(mbeg,8); @@ -1711,10 +1804,10 @@ void expand_mask(char *Mask,BOOL doext) expand_one(mext,3); pstrcpy(Mask,dirpart); - if (*dirpart || absolute) strcat(Mask,"\\"); - strcat(Mask,mbeg); - strcat(Mask,"."); - strcat(Mask,mext); + if (*dirpart || absolute) pstrcat(Mask,"\\"); + pstrcat(Mask,mbeg); + pstrcat(Mask,"."); + pstrcat(Mask,mext); DEBUG(6,("Mask expanded to [%s]\n",Mask)); } @@ -1728,6 +1821,15 @@ BOOL strhasupper(char *s) while (*s) { #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -1745,9 +1847,14 @@ BOOL strhasupper(char *s) else #endif /* KANJI_WIN95_COMPATIBILITY */ { - if (isupper(*s)) - return(True); - s++; + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (isupper(*s)) + return(True); + s++; + } } } return(False); @@ -1761,6 +1868,15 @@ BOOL strhaslower(char *s) while (*s) { #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -1786,9 +1902,14 @@ BOOL strhaslower(char *s) else #endif /* KANJI_WIN95_COMPATIBILITY */ { - if (islower(*s)) - return(True); - s++; + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (islower(*s)) + return(True); + s++; + } } } return(False); @@ -1802,6 +1923,15 @@ int count_chars(char *s,char c) int count=0; #if !defined(KANJI_WIN95_COMPATIBILITY) + /* + * For completeness we should put in equivalent code for code pages + * 949 (Korean hangul) and 950 (Big5 Traditional Chinese) here - but + * doubt anyone wants Samba to behave differently from Win95 and WinNT + * here. They both treat full width ascii characters as case senstive + * filenames (ie. they don't do the work we do here). + * JRA. + */ + if(lp_client_code_page() == KANJI_CODEPAGE) { /* Win95 treats full width ascii characters as case sensitive. */ @@ -1822,9 +1952,14 @@ int count_chars(char *s,char c) { while (*s) { - if (*s == c) - count++; - s++; + int skip = skip_multibyte_char( *s ); + if( skip != 0 ) + s += skip; + else { + if (*s == c) + count++; + s++; + } } } return(count); @@ -1934,6 +2069,10 @@ int write_socket(int fd,char *buf,int len) ret = write_data(fd,buf,len); DEBUG(6,("write_socket(%d,%d) wrote %d\n",fd,len,ret)); + if(ret <= 0) + DEBUG(0,("write_socket: Error writing %d bytes to socket %d: ERRNO = %s\n", + len, fd, strerror(errno) )); + return(ret); } @@ -1943,20 +2082,23 @@ read from a socket int read_udp_socket(int fd,char *buf,int len) { int ret; - struct sockaddr sock; + struct sockaddr_in sock; int socklen; socklen = sizeof(sock); bzero((char *)&sock,socklen); bzero((char *)&lastip,sizeof(lastip)); - ret = recvfrom(fd,buf,len,0,&sock,&socklen); + ret = recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen); if (ret <= 0) { DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno))); return(0); } - lastip = *(struct in_addr *) &sock.sa_data[2]; - lastport = ntohs(((struct sockaddr_in *)&sock)->sin_port); + lastip = sock.sin_addr; + lastport = ntohs(sock.sin_port); + + DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %d\n", + inet_ntoa(lastip), lastport, ret)); return(ret); } @@ -1984,7 +2126,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out) if (mincnt == 0) mincnt = maxcnt; while (nread < mincnt) { +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ readret = read(fd, buf + nread, maxcnt - nread); +#endif /* WITH_SSL */ + if (readret == 0) { smb_read_error = READ_EOF; return -1; @@ -2029,7 +2180,16 @@ int read_with_timeout(int fd,char *buf,int mincnt,int maxcnt,long time_out) return -1; } - readret = read(fd, buf+nread, maxcnt-nread); +#ifdef WITH_SSL + if(fd == sslFd){ + readret = SSL_read(ssl, buf + nread, maxcnt - nread); + }else{ + readret = read(fd, buf + nread, maxcnt - nread); + } +#else /* WITH_SSL */ + readret = read(fd, buf+nread, maxcnt-nread); +#endif /* WITH_SSL */ + if (readret == 0) { /* we got EOF on the file descriptor */ smb_read_error = READ_EOF; @@ -2112,18 +2272,29 @@ int read_data(int fd,char *buffer,int N) smb_read_error = 0; while (total < N) - { + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_read(ssl, buffer + total, N - total); + }else{ ret = read(fd,buffer + total,N - total); - if (ret == 0) { - smb_read_error = READ_EOF; - return 0; - } - if (ret == -1) { - smb_read_error = READ_ERROR; - return -1; - } - total += ret; } +#else /* WITH_SSL */ + ret = read(fd,buffer + total,N - total); +#endif /* WITH_SSL */ + + if (ret == 0) + { + smb_read_error = READ_EOF; + return 0; + } + if (ret == -1) + { + smb_read_error = READ_ERROR; + return -1; + } + total += ret; + } return total; } @@ -2137,14 +2308,22 @@ int write_data(int fd,char *buffer,int N) int ret; while (total < N) - { + { +#ifdef WITH_SSL + if(fd == sslFd){ + ret = SSL_write(ssl,buffer + total,N - total); + }else{ ret = write(fd,buffer + total,N - total); + } +#else /* WITH_SSL */ + ret = write(fd,buffer + total,N - total); +#endif /* WITH_SSL */ - if (ret == -1) return -1; - if (ret == 0) return total; + if (ret == -1) return -1; + if (ret == 0) return total; - total += ret; - } + total += ret; + } return total; } @@ -2228,38 +2407,30 @@ int transfer_file(int infd,int outfd,int n,char *header,int headlen,int align) /**************************************************************************** read 4 bytes of a smb packet and return the smb length of the packet -possibly store the result in the buffer +store the result in the buffer +This version of the function will return a length of zero on receiving +a keepalive packet. ****************************************************************************/ -int read_smb_length(int fd,char *inbuf,int timeout) +static int read_smb_length_return_keepalive(int fd,char *inbuf,int timeout) { - char *buffer; - char buf[4]; int len=0, msg_type; BOOL ok=False; - if (inbuf) - buffer = inbuf; - else - buffer = buf; - while (!ok) { if (timeout > 0) - ok = (read_with_timeout(fd,buffer,4,4,timeout) == 4); + ok = (read_with_timeout(fd,inbuf,4,4,timeout) == 4); else - ok = (read_data(fd,buffer,4) == 4); + ok = (read_data(fd,inbuf,4) == 4); if (!ok) return(-1); - len = smb_len(buffer); - msg_type = CVAL(buffer,0); + len = smb_len(inbuf); + msg_type = CVAL(inbuf,0); if (msg_type == 0x85) - { - DEBUG(5,("Got keepalive packet\n")); - ok = False; - } + DEBUG(5,("Got keepalive packet\n")); } DEBUG(10,("got smb length of %d\n",len)); @@ -2267,13 +2438,39 @@ int read_smb_length(int fd,char *inbuf,int timeout) return(len); } +/**************************************************************************** +read 4 bytes of a smb packet and return the smb length of the packet +store the result in the buffer. This version of the function will +never return a session keepalive (length of zero). +****************************************************************************/ +int read_smb_length(int fd,char *inbuf,int timeout) +{ + int len; + + for(;;) + { + len = read_smb_length_return_keepalive(fd, inbuf, timeout); + + if(len < 0) + return len; + + /* Ignore session keepalives. */ + if(CVAL(inbuf,0) != 0x85) + break; + } + return len; +} /**************************************************************************** - read an smb from a fd. -The timeout is in milli seconds + read an smb from a fd. Note that the buffer *MUST* be of size + BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milli seconds. + + This function will return on a + receipt of a session keepalive packet. ****************************************************************************/ -BOOL receive_smb(int fd,char *buffer,int timeout) +BOOL receive_smb(int fd,char *buffer, int timeout) { int len,ret; @@ -2281,8 +2478,8 @@ BOOL receive_smb(int fd,char *buffer,int timeout) bzero(buffer,smb_size + 100); - len = read_smb_length(fd,buffer,timeout); - if (len == -1) + len = read_smb_length_return_keepalive(fd,buffer,timeout); + if (len < 0) return(False); if (len > BUFFER_SIZE) { @@ -2291,38 +2488,232 @@ BOOL receive_smb(int fd,char *buffer,int timeout) exit(1); } - ret = read_data(fd,buffer+4,len); - if (ret != len) { - smb_read_error = READ_ERROR; - return False; + if(len > 0) { + ret = read_data(fd,buffer+4,len); + if (ret != len) { + smb_read_error = READ_ERROR; + return False; + } } - return(True); } -#ifdef USE_OPLOCKS /**************************************************************************** - Do a select on an two fd's - with timeout. + read an smb from a fd ignoring all keepalive packets. Note that the buffer + *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN. + The timeout is in milli seconds + + This is exactly the same as receive_smb except that it never returns + a session keepalive packet (just as receive_smb used to do). + receive_smb was changed to return keepalives as the oplock processing means this call + should never go into a blocking read. +****************************************************************************/ - If the first smbfd is ready then read an smb from it. - if the second (loopback UDP) fd is ready then read a message - from it and setup the buffer header to identify the length - and from address. - Returns False on timeout or error. - Else returns True. +BOOL client_receive_smb(int fd,char *buffer, int timeout) +{ + BOOL ret; + + for(;;) + { + ret = receive_smb(fd, buffer, timeout); + + if(ret == False) + return ret; + + /* Ignore session keepalive packets. */ + if(CVAL(buffer,0) != 0x85) + break; + } + return ret; +} +/**************************************************************************** + read a message from a udp fd. The timeout is in milli seconds ****************************************************************************/ -BOOL receive_message_or_smb(int smbfd, int oplock_fd, - char *buffer, int buffer_len, - int timeout, BOOL *got_smb) +BOOL receive_local_message(int fd, char *buffer, int buffer_len, int timeout) +{ + struct sockaddr_in from; + int fromlen = sizeof(from); + int32 msg_len = 0; + + smb_read_error = 0; + + if(timeout != 0) + { + struct timeval to; + fd_set fds; + int selrtn; + + FD_ZERO(&fds); + FD_SET(fd,&fds); + + to.tv_sec = timeout / 1000; + to.tv_usec = (timeout % 1000) * 1000; + + selrtn = sys_select(&fds,&to); + + /* Check if error */ + if(selrtn == -1) + { + /* something is wrong. Maybe the socket is dead? */ + smb_read_error = READ_ERROR; + return False; + } + + /* Did we timeout ? */ + if (selrtn == 0) + { + smb_read_error = READ_TIMEOUT; + return False; + } + } + + /* + * Read a loopback udp message. + */ + msg_len = recvfrom(fd, &buffer[UDP_CMD_HEADER_LEN], + buffer_len - UDP_CMD_HEADER_LEN, 0, + (struct sockaddr *)&from, &fromlen); + + if(msg_len < 0) + { + DEBUG(0,("receive_local_message. Error in recvfrom. (%s).\n",strerror(errno))); + return False; + } + + /* Validate message length. */ + if(msg_len > (buffer_len - UDP_CMD_HEADER_LEN)) + { + DEBUG(0,("receive_local_message: invalid msg_len (%d) max can be %d\n", + msg_len, + buffer_len - UDP_CMD_HEADER_LEN)); + return False; + } + + /* Validate message from address (must be localhost). */ + if(from.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) + { + DEBUG(0,("receive_local_message: invalid 'from' address \ +(was %x should be 127.0.0.1\n", from.sin_addr.s_addr)); + return False; + } + + /* Setup the message header */ + SIVAL(buffer,UDP_CMD_LEN_OFFSET,msg_len); + SSVAL(buffer,UDP_CMD_PORT_OFFSET,ntohs(from.sin_port)); + + return True; +} + +/**************************************************************************** + structure to hold a linked list of local messages. + for processing. +****************************************************************************/ + +typedef struct _message_list { + struct _message_list *msg_next; + char *msg_buf; + int msg_len; +} pending_message_list; + +static pending_message_list *smb_msg_head = NULL; + +/**************************************************************************** + Function to push a linked list of local messages ready + for processing. +****************************************************************************/ + +static BOOL push_local_message(pending_message_list **pml, char *buf, int msg_len) +{ + pending_message_list *msg = (pending_message_list *) + malloc(sizeof(pending_message_list)); + + if(msg == NULL) + { + DEBUG(0,("push_message: malloc fail (1)\n")); + return False; + } + + msg->msg_buf = (char *)malloc(msg_len); + if(msg->msg_buf == NULL) + { + DEBUG(0,("push_local_message: malloc fail (2)\n")); + free((char *)msg); + return False; + } + + memcpy(msg->msg_buf, buf, msg_len); + msg->msg_len = msg_len; + + msg->msg_next = *pml; + *pml = msg; + + return True; +} + +/**************************************************************************** + Function to push a linked list of local smb messages ready + for processing. +****************************************************************************/ + +BOOL push_smb_message(char *buf, int msg_len) +{ + return push_local_message(&smb_msg_head, buf, msg_len); +} + +/**************************************************************************** + Do a select on an two fd's - with timeout. + + If a local udp message has been pushed onto the + queue (this can only happen during oplock break + processing) return this first. + + If a pending smb message has been pushed onto the + queue (this can only happen during oplock break + processing) return this next. + + If the first smbfd is ready then read an smb from it. + if the second (loopback UDP) fd is ready then read a message + from it and setup the buffer header to identify the length + and from address. + Returns False on timeout or error. + Else returns True. + +The timeout is in milli seconds +****************************************************************************/ +BOOL receive_message_or_smb(int smbfd, int oplock_fd, + char *buffer, int buffer_len, + int timeout, BOOL *got_smb) { fd_set fds; int selrtn; struct timeval to; + smb_read_error = 0; + *got_smb = False; - + + /* + * Check to see if we already have a message on the smb queue. + * If so - copy and return it. + */ + + if(smb_msg_head) + { + pending_message_list *msg = smb_msg_head; + memcpy(buffer, msg->msg_buf, MIN(buffer_len, msg->msg_len)); + smb_msg_head = msg->msg_next; + + /* Free the message we just copied. */ + free((char *)msg->msg_buf); + free((char *)msg); + *got_smb = True; + + DEBUG(5,("receive_message_or_smb: returning queued smb message.\n")); + return True; + } + FD_ZERO(&fds); FD_SET(smbfd,&fds); FD_SET(oplock_fd,&fds); @@ -2352,36 +2743,9 @@ BOOL receive_message_or_smb(int smbfd, int oplock_fd, } else { - /* - * Read a udp message. - */ - struct sockaddr_in from; - int fromlen = sizeof(from); - int32 msg_len = 0; - uint16 port = 0; - - msg_len = recvfrom(oplock_fd, &buffer[6+sizeof(struct in_addr)], - buffer_len - (6 + sizeof(struct in_addr)), 0, - (struct sockaddr *)&from, &fromlen); - - if(msg_len < 0) - { - DEBUG(0,("Invalid loopback packet ! (%s).\n",strerror(errno))); - return False; - } - - port = ntohs(from.sin_port); - - /* Setup the message header */ - SIVAL(buffer,0,msg_len); - SSVAL(buffer,4,port); - memcpy(&buffer[6],(char *)&from.sin_addr,sizeof(struct in_addr)); - + return receive_local_message(oplock_fd, buffer, buffer_len, 0); } - - return True; } -#endif /* USE_OPLOCKS */ /**************************************************************************** send an smb to a fd @@ -2437,24 +2801,30 @@ int name_extract(char *buf,int ofs,char *name) { char *p = name_ptr(buf,ofs); int d = PTR_DIFF(p,buf+ofs); - strcpy(name,""); + pstrcpy(name,""); if (d < -50 || d > 50) return(0); return(name_interpret(p,name)); -} +} - /**************************************************************************** return the total storage length of a mangled name ****************************************************************************/ -int name_len(char *s) -{ - char *s0=s; - unsigned char c = *(unsigned char *)s; - if ((c & 0xC0) == 0xC0) +int name_len( char *s ) + { + int len; + + /* If the two high bits of the byte are set, return 2. */ + if( 0xC0 == (*(unsigned char *)s & 0xC0) ) return(2); - while (*s) s += (*s)+1; - return(PTR_DIFF(s,s0)+1); -} + + /* Add up the length bytes. */ + for( len = 1; (*s); s += (*s) + 1 ) + { + len += *s + 1; + } + + return( len ); + } /* name_len */ /**************************************************************************** send a single packet to a port on another machine @@ -2575,7 +2945,7 @@ BOOL string_init(char **dest,char *src) return False; } - strcpy(*dest,src); + pstrcpy(*dest,src); } return(True); } @@ -2637,12 +3007,12 @@ BOOL string_sub(char *s,char *pattern,char *insert) return(ret); } - - /********************************************************* * Recursive routine that is called by mask_match. -* Does the actual matching. +* Does the actual matching. Returns True if matched, +* False if failed. *********************************************************/ + BOOL do_match(char *str, char *regexp, int case_sig) { char *p; @@ -2655,48 +3025,61 @@ BOOL do_match(char *str, char *regexp, int case_sig) case '*': /* Look for a character matching - the one after the '*' */ + the one after the '*' */ p++; if(!*p) - return True; /* Automatic match */ + return True; /* Automatic match */ while(*str) { - while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) - str++; - if(do_match(str,p,case_sig)) - return True; - if(!*str) - return False; - else - str++; + while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str)))) + str++; + /* Now eat all characters that match, as + we want the *last* character to match. */ + while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) + str++; + str--; /* We've eaten the match char after the '*' */ + if(do_match(str,p,case_sig)) { + return True; + } + if(!*str) { + return False; + } else { + str++; + } } return False; default: if(case_sig) { - if(*str != *p) - return False; + if(*str != *p) { + return False; + } } else { - if(toupper(*str) != toupper(*p)) - return False; + if(toupper(*str) != toupper(*p)) { + return False; + } } str++, p++; break; } } + if(!*p && !*str) return True; - if (!*p && str[0] == '.' && str[1] == 0) + if (!*p && str[0] == '.' && str[1] == 0) { return(True); + } - if (!*str && *p == '?') - { - while (*p == '?') p++; - return(!*p); - } + if (!*str && *p == '?') { + while (*p == '?') + p++; + return(!*p); + } - if(!*str && (*p == '*' && p[1] == '\0')) + if(!*str && (*p == '*' && p[1] == '\0')) { return True; + } + return False; } @@ -2705,106 +3088,239 @@ BOOL do_match(char *str, char *regexp, int case_sig) * Routine to match a given string with a regexp - uses * simplified regexp that takes * and ? only. Case can be * significant or not. +* The 8.3 handling was rewritten by Ums Harald *********************************************************/ + BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2) { char *p; - pstring p1, p2; + pstring t_pattern, t_filename, te_pattern, te_filename; fstring ebase,eext,sbase,sext; - BOOL matched; + BOOL matched = False; /* Make local copies of str and regexp */ - StrnCpy(p1,regexp,sizeof(pstring)-1); - StrnCpy(p2,str,sizeof(pstring)-1); - - if (!strchr(p2,'.')) { - strcat(p2,"."); - } + pstrcpy(t_pattern,regexp); + pstrcpy(t_filename,str); -/* - if (!strchr(p1,'.')) { - strcat(p1,"."); - } -*/ +#if 0 + /* + * Not sure if this is a good idea. JRA. + */ + if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False)) + trans2 = False; +#endif #if 0 - if (strchr(p1,'.')) - { - string_sub(p1,"*.*","*"); - string_sub(p1,".*","*"); - } + if (!strchr(t_filename,'.')) { + pstrcat(t_filename,"."); + } #endif /* Remove any *? and ** as they are meaningless */ - for(p = p1; *p; p++) - while( *p == '*' && (p[1] == '?' ||p[1] == '*')) - (void)strcpy( &p[1], &p[2]); + string_sub(t_pattern, "*?", "*"); + string_sub(t_pattern, "**", "*"); + + if (strequal(t_pattern,"*")) + return(True); - if (strequal(p1,"*")) return(True); + DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig)); - DEBUG(5,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + if(trans2) { + /* + * Match each component of the regexp, split up by '.' + * characters. + */ + char *fp, *rp, *cp2, *cp1; + BOOL last_wcard_was_star = False; + int num_path_components, num_regexp_components; + + pstrcpy(te_pattern,t_pattern); + pstrcpy(te_filename,t_filename); + /* + * Remove multiple "*." patterns. + */ + string_sub(te_pattern, "*.*.", "*."); + num_regexp_components = count_chars(te_pattern, '.'); + num_path_components = count_chars(te_filename, '.'); - if (trans2) { - fstrcpy(ebase,p1); - fstrcpy(sbase,p2); + /* + * Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z + */ + if(num_regexp_components == 0) + matched = do_match( te_filename, te_pattern, case_sig); + else { + for( cp1 = te_pattern, cp2 = te_filename; cp1;) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + rp = strchr(cp1, '.'); + if(rp) + *rp = '\0'; + + if(cp1[strlen(cp1)-1] == '*') + last_wcard_was_star = True; + else + last_wcard_was_star = False; + + if(!do_match(cp2, cp1, case_sig)) + break; + + cp1 = rp ? rp + 1 : NULL; + cp2 = fp ? fp + 1 : ""; + + if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) { + /* Eat the extra path components. */ + int i; + + for(i = 0; i < num_path_components - num_regexp_components; i++) { + fp = strchr(cp2, '.'); + if(fp) + *fp = '\0'; + + if((cp1 != NULL) && do_match( cp2, cp1, case_sig)) { + cp2 = fp ? fp + 1 : ""; + break; + } + cp2 = fp ? fp + 1 : ""; + } + num_path_components -= i; + } + } + if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star)) + matched = True; + } } else { - if ((p=strrchr(p1,'.'))) { - *p = 0; - fstrcpy(ebase,p1); - fstrcpy(eext,p+1); + + /* ------------------------------------------------- + * Behaviour of Win95 + * for 8.3 filenames and 8.3 Wildcards + * ------------------------------------------------- + */ + if (strequal (t_filename, ".")) { + /* + * Patterns: *.* *. ?. ? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?")) + matched = True; + } else if (strequal (t_filename, "..")) { + /* + * Patterns: *.* *. ?. ? *.? are valid + * + */ + if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") || + strequal(t_pattern, "?.") || strequal(t_pattern, "?") || + strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*")) + matched = True; } else { - fstrcpy(ebase,p1); - eext[0] = 0; - } - if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) { - *p = 0; - fstrcpy(sbase,p2); - fstrcpy(sext,p+1); - } else { - fstrcpy(sbase,p2); - fstrcpy(sext,""); - } - } + if ((p = strrchr (t_pattern, '.'))) { + /* + * Wildcard has a suffix. + */ + *p = 0; + fstrcpy (ebase, t_pattern); + if (p[1]) { + fstrcpy (eext, p + 1); + } else { + /* pattern ends in DOT: treat as if there is no DOT */ + *eext = 0; + if (strequal (ebase, "*")) + return (True); + } + } else { + /* + * No suffix for wildcard. + */ + fstrcpy (ebase, t_pattern); + eext[0] = 0; + } - matched = do_match(sbase,ebase,case_sig) && - (trans2 || do_match(sext,eext,case_sig)); + p = strrchr (t_filename, '.'); + if (p && (p[1] == 0) ) { + /* + * Filename has an extension of '.' only. + */ + *p = 0; /* nuke dot at end of string */ + p = 0; /* and treat it as if there is no extension */ + } + + if (p) { + /* + * Filename has an extension. + */ + *p = 0; + fstrcpy (sbase, t_filename); + fstrcpy (sext, p + 1); + if (*eext) { + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + /* pattern has no extension */ + /* Really: match complete filename with pattern ??? means exactly 3 chars */ + matched = do_match(str, ebase, case_sig); + } + } else { + /* + * Filename has no extension. + */ + fstrcpy (sbase, t_filename); + fstrcpy (sext, ""); + if (*eext) { + /* pattern has extension */ + matched = do_match(sbase, ebase, case_sig) + && do_match(sext, eext, case_sig); + } else { + matched = do_match(sbase, ebase, case_sig); +#ifdef EMULATE_WEIRD_W95_MATCHING + /* + * Even Microsoft has some problems + * Behaviour Win95 -> local disk + * is different from Win95 -> smb drive from Nt 4.0 + * This branch would reflect the Win95 local disk behaviour + */ + if (!matched) { + /* a? matches aa and a in w95 */ + fstrcat (sbase, "."); + matched = do_match(sbase, ebase, case_sig); + } +#endif + } + } + } + } - DEBUG(5,("mask_match returning %d\n", matched)); + DEBUG(8,("mask_match returning %d\n", matched)); return matched; } - - /**************************************************************************** become a daemon, discarding the controlling terminal ****************************************************************************/ void become_daemon(void) { -#ifndef NO_FORK_DEBUG - if (fork()) - exit(0); + if (fork()) { + _exit(0); + } /* detach from the terminal */ -#ifdef USE_SETSID - setsid(); -#else /* USE_SETSID */ -#ifdef TIOCNOTTY - { - int i = open("/dev/tty", O_RDWR); - if (i >= 0) - { - ioctl(i, (int) TIOCNOTTY, (char *)0); - close(i); - } - } -#endif /* TIOCNOTTY */ -#endif /* USE_SETSID */ - /* Close fd's 0,1,2. Needed if started by rsh */ - close_low_fds(); -#endif /* NO_FORK_DEBUG */ +#ifdef HAVE_SETSID + setsid(); +#elif defined(TIOCNOTTY) + { + int i = open("/dev/tty", O_RDWR); + if (i != -1) { + ioctl(i, (int) TIOCNOTTY, (char *)0); + close(i); + } + } +#endif /* HAVE_SETSID */ + + /* Close fd's 0,1,2. Needed if started by rsh */ + close_low_fds(); } @@ -2903,7 +3419,7 @@ int set_filelen(int fd, long len) extend a file with ftruncate. Provide alternate implementation for this */ -#if FTRUNCATE_CAN_EXTEND +#ifdef HAVE_FTRUNCATE_EXTEND return ftruncate(fd, len); #else struct stat st; @@ -2972,11 +3488,11 @@ char *dirname_dos(char *path,char *buf) char *p = strrchr(path,'\\'); if (!p) - strcpy(buf,path); + pstrcpy(buf,path); else { *p = 0; - strcpy(buf,path); + pstrcpy(buf,path); *p = '\\'; } @@ -2992,9 +3508,9 @@ static char *filename_dos(char *path,char *buf) char *p = strrchr(path,'\\'); if (!p) - strcpy(buf,path); + pstrcpy(buf,path); else - strcpy(buf,p+1); + pstrcpy(buf,p+1); return(buf); } @@ -3025,21 +3541,6 @@ void *Realloc(void *p,int size) return(ret); } -#ifdef NOSTRDUP -/**************************************************************************** -duplicate a string -****************************************************************************/ - char *strdup(char *s) -{ - char *ret = NULL; - if (!s) return(NULL); - ret = (char *)malloc(strlen(s)+1); - if (!ret) return(NULL); - strcpy(ret,s); - return(ret); -} -#endif - /**************************************************************************** Signal handler for SIGPIPE (write on a disconnected socket) @@ -3070,7 +3571,7 @@ BOOL get_myname(char *my_name,struct in_addr *ip) /* get host info */ if ((hp = Get_Hostbyname(hostname)) == 0) { - DEBUG(0,( "Get_Hostbyname: Unknown host %s.\n",hostname)); + DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",hostname)); return False; } @@ -3119,13 +3620,14 @@ int open_socket_in(int type, int port, int dlevel,uint32 socket_addr) /* get host info */ if ((hp = Get_Hostbyname(host_name)) == 0) { - DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",host_name)); + DEBUG(0,( "Get_Hostbyname: Unknown host %s\n",host_name)); return -1; } bzero((char *)&sock,sizeof(sock)); memcpy((char *)&sock.sin_addr,(char *)hp->h_addr, hp->h_length); -#if defined(__FreeBSD__) || defined(NETBSD) /* XXX not the right ifdef */ + +#ifdef HAVE_SOCK_SIN_LEN sock.sin_len = sizeof(sock); #endif sock.sin_port = htons( port ); @@ -3145,8 +3647,8 @@ int open_socket_in(int type, int port, int dlevel,uint32 socket_addr) { if (port) { if (port == SMB_PORT || port == NMB_PORT) - DEBUG(dlevel,("bind failed on port %d socket_addr=%x (%s)\n", - port,socket_addr,strerror(errno))); + DEBUG(dlevel,("bind failed on port %d socket_addr=%s (%s)\n", + port,inet_ntoa(sock.sin_addr),strerror(errno))); close(res); if (dlevel > 0 && port < 1000) @@ -3220,6 +3722,7 @@ connect_again: if (ret < 0) { DEBUG(1,("error connecting to %s:%d (%s)\n", inet_ntoa(*addr),port,strerror(errno))); + close(res); return -1; } @@ -3298,6 +3801,10 @@ uint32 interpret_addr(char *str) DEBUG(3,("Get_Hostbyname: Unknown host. %s\n",str)); return 0; } + if(hp->h_addr == NULL) { + DEBUG(3,("Get_Hostbyname: host address is invalid for host %s\n",str)); + return 0; + } putip((char *)&res,(char *)hp->h_addr); } @@ -3382,130 +3889,415 @@ static BOOL matchname(char *remotehost,struct in_addr addr) static BOOL global_client_name_done = False; static BOOL global_client_addr_done = False; -void reset_globals_after_fork() +void reset_globals_after_fork(void) { global_client_name_done = False; global_client_addr_done = False; + + /* + * Re-seed the random crypto generator, so all smbd's + * started from the same parent won't generate the same + * sequence. + */ + { + unsigned char dummy; + generate_random_buffer( &dummy, 1, True); + } } /******************************************************************* return the DNS name of the client ******************************************************************/ -char *client_name(void) -{ - extern int Client; - struct sockaddr sa; - struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); - int length = sizeof(sa); - static pstring name_buf; - struct hostent *hp; - - if (global_client_name_done) - return name_buf; - - strcpy(name_buf,"UNKNOWN"); - - if (getpeername(Client, &sa, &length) < 0) { - DEBUG(0,("getpeername failed\n")); - return name_buf; - } - - /* Look up the remote host name. */ - if ((hp = gethostbyaddr((char *) &sockin->sin_addr, - sizeof(sockin->sin_addr), - AF_INET)) == 0) { - DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr())); - StrnCpy(name_buf,client_addr(),sizeof(name_buf) - 1); - } else { - StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1); - if (!matchname(name_buf, sockin->sin_addr)) { - DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr())); - strcpy(name_buf,"UNKNOWN"); - } - } - global_client_name_done = True; - return name_buf; +char *client_name(int fd) +{ + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static pstring name_buf; + struct hostent *hp; + static int last_fd=-1; + + if (global_client_name_done && last_fd == fd) + return name_buf; + + last_fd = fd; + global_client_name_done = False; + + pstrcpy(name_buf,"UNKNOWN"); + + if (fd == -1) { + return name_buf; + } + + if (getpeername(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return name_buf; + } + + /* Look up the remote host name. */ + if ((hp = gethostbyaddr((char *) &sockin->sin_addr, + sizeof(sockin->sin_addr), + AF_INET)) == 0) { + DEBUG(1,("Gethostbyaddr failed for %s\n",client_addr(fd))); + StrnCpy(name_buf,client_addr(fd),sizeof(name_buf) - 1); + } else { + StrnCpy(name_buf,(char *)hp->h_name,sizeof(name_buf) - 1); + if (!matchname(name_buf, sockin->sin_addr)) { + DEBUG(0,("Matchname failed on %s %s\n",name_buf,client_addr(fd))); + pstrcpy(name_buf,"UNKNOWN"); + } + } + global_client_name_done = True; + return name_buf; } /******************************************************************* return the IP addr of the client as a string ******************************************************************/ -char *client_addr(void) +char *client_addr(int fd) { - extern int Client; - struct sockaddr sa; - struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); - int length = sizeof(sa); - static fstring addr_buf; - - if (global_client_addr_done) - return addr_buf; + struct sockaddr sa; + struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa); + int length = sizeof(sa); + static fstring addr_buf; + static int last_fd = -1; - strcpy(addr_buf,"0.0.0.0"); + if (global_client_addr_done && fd == last_fd) + return addr_buf; - if (getpeername(Client, &sa, &length) < 0) { - DEBUG(0,("getpeername failed\n")); - return addr_buf; - } + last_fd = fd; + global_client_addr_done = False; - fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + fstrcpy(addr_buf,"0.0.0.0"); - global_client_addr_done = True; - return addr_buf; + if (fd == -1) { + return addr_buf; + } + + if (getpeername(fd, &sa, &length) < 0) { + DEBUG(0,("getpeername failed\n")); + return addr_buf; + } + + fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr)); + + global_client_addr_done = True; + return addr_buf; } -/******************************************************************* -sub strings with useful parameters -Rewritten by Stefaan A Eeckels and -Paul Rippin -********************************************************************/ -void standard_sub_basic(char *str) - { - char *s, *p; - char pidstr[10]; - struct passwd *pass; +#if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) +/****************************************************************** + Remove any mount options such as -rsize=2048,wsize=2048 etc. + Based on a fix from . +*******************************************************************/ - for (s = str ; (p = strchr(s,'%')) != NULL ; s = p ) - { - switch (*(p+1)) - { - case 'G' : if ((pass = Get_Pwnam(sesssetup_user,False))!=NULL) - string_sub(p,"%G",gidtoname(pass->pw_gid)); - else - p += 2; - break; - case 'I' : string_sub(p,"%I",client_addr()); break; - case 'L' : string_sub(p,"%L",local_machine); break; - case 'M' : string_sub(p,"%M",client_name()); break; - case 'R' : string_sub(p,"%R",remote_proto); break; - case 'T' : string_sub(p,"%T",timestring()); break; - case 'U' : string_sub(p,"%U",sesssetup_user); break; - case 'a' : string_sub(p,"%a",remote_arch); break; - case 'd' : sprintf(pidstr,"%d",(int)getpid()); - string_sub(p,"%d",pidstr); - break; - case 'h' : string_sub(p,"%h",myhostname); break; - case 'm' : string_sub(p,"%m",remote_machine); break; - case 'v' : string_sub(p,"%v",VERSION); break; - case '\0' : p++; break; /* don't run off end if last character is % */ - default : p+=2; break; +static void strip_mount_options( pstring *str) +{ + if (**str == '-') + { + char *p = *str; + while(*p && !isspace(*p)) + p++; + while(*p && isspace(*p)) + p++; + if(*p) { + pstring tmp_str; + + pstrcpy(tmp_str, p); + pstrcpy(*str, tmp_str); } } - return; } /******************************************************************* -are two IPs on the same subnet? -********************************************************************/ -BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) -{ - uint32 net1,net2,nmask; + Patch from jkf@soton.ac.uk + Split Luke's automount_server into YP lookup and string splitter + so can easily implement automount_path(). + As we may end up doing both, cache the last YP result. +*******************************************************************/ - nmask = ntohl(mask.s_addr); - net1 = ntohl(ip1.s_addr); - net2 = ntohl(ip2.s_addr); - - return((net1 & nmask) == (net2 & nmask)); +#ifdef NISPLUS_HOME +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + char *nis_map = (char *)lp_nis_home_map_name(); + + char nis_domain[NIS_MAXNAMELEN + 1]; + char buffer[NIS_MAXATTRVAL + 1]; + nis_result *result; + nis_object *object; + entry_obj *entry; + + strncpy(nis_domain, (char *)nis_local_directory(), NIS_MAXNAMELEN); + nis_domain[NIS_MAXNAMELEN] = '\0'; + + DEBUG(5, ("NIS+ Domain: %s\n", nis_domain)); + + if (strcmp(user_name, last_key)) + { + slprintf(buffer, sizeof(buffer)-1, "[%s=%s]%s.%s", "key", user_name, nis_map, nis_domain); + DEBUG(5, ("NIS+ querystring: %s\n", buffer)); + + if (result = nis_list(buffer, RETURN_RESULT, NULL, NULL)) + { + if (result->status != NIS_SUCCESS) + { + DEBUG(3, ("NIS+ query failed: %s\n", nis_sperrno(result->status))); + fstrcpy(last_key, ""); pstrcpy(last_value, ""); + } + else + { + object = result->objects.objects_val; + if (object->zo_data.zo_type == ENTRY_OBJ) + { + entry = &object->zo_data.objdata_u.en_data; + DEBUG(5, ("NIS+ entry type: %s\n", entry->en_type)); + DEBUG(3, ("NIS+ result: %s\n", entry->en_cols.en_cols_val[1].ec_value.ec_value_val)); + + pstrcpy(last_value, entry->en_cols.en_cols_val[1].ec_value.ec_value_val); + string_sub(last_value, "&", user_name); + fstrcpy(last_key, user_name); + } + } + } + nis_freeresult(result); + } + + strip_mount_options(&last_value); + + DEBUG(4, ("NIS+ Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; +} +#else /* NISPLUS_HOME */ +static char *automount_lookup(char *user_name) +{ + static fstring last_key = ""; + static pstring last_value = ""; + + int nis_error; /* returned by yp all functions */ + char *nis_result; /* yp_match inits this */ + int nis_result_len; /* and set this */ + char *nis_domain; /* yp_get_default_domain inits this */ + char *nis_map = (char *)lp_nis_home_map_name(); + + if ((nis_error = yp_get_default_domain(&nis_domain)) != 0) + { + DEBUG(3, ("YP Error: %s\n", yperr_string(nis_error))); + return last_value; + } + + DEBUG(5, ("NIS Domain: %s\n", nis_domain)); + + if (!strcmp(user_name, last_key)) + { + nis_result = last_value; + nis_result_len = strlen(last_value); + nis_error = 0; + } + else + { + if ((nis_error = yp_match(nis_domain, nis_map, + user_name, strlen(user_name), + &nis_result, &nis_result_len)) != 0) + { + DEBUG(3, ("YP Error: \"%s\" while looking up \"%s\" in map \"%s\"\n", + yperr_string(nis_error), user_name, nis_map)); + } + if (!nis_error && nis_result_len >= sizeof(pstring)) + { + nis_result_len = sizeof(pstring)-1; + } + fstrcpy(last_key, user_name); + strncpy(last_value, nis_result, nis_result_len); + last_value[nis_result_len] = '\0'; + } + + strip_mount_options(&last_value); + + DEBUG(4, ("YP Lookup: %s resulted in %s\n", user_name, last_value)); + return last_value; +} +#endif /* NISPLUS_HOME */ +#endif + +/******************************************************************* + Patch from jkf@soton.ac.uk + This is Luke's original function with the NIS lookup code + moved out to a separate function. +*******************************************************************/ + +char *automount_server(char *user_name) +{ + static pstring server_name; + + /* use the local machine name as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + pstrcpy(server_name, local_machine); + +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) + + if (lp_nis_home_map()) + { + int home_server_len; + char *automount_value = automount_lookup(user_name); + home_server_len = strcspn(automount_value,":"); + DEBUG(5, ("NIS lookup succeeded. Home server length: %d\n",home_server_len)); + if (home_server_len > sizeof(pstring)) + { + home_server_len = sizeof(pstring); + } + strncpy(server_name, automount_value, home_server_len); + server_name[home_server_len] = '\0'; + } +#endif + + DEBUG(4,("Home server: %s\n", server_name)); + + return server_name; +} + +/******************************************************************* + Patch from jkf@soton.ac.uk + Added this to implement %p (NIS auto-map version of %H) +*******************************************************************/ + +char *automount_path(char *user_name) +{ + static pstring server_path; + + /* use the passwd entry as the default */ + /* this will be the default if WITH_AUTOMOUNT is not used or fails */ + /* pstrcpy() copes with get_home_dir() returning NULL */ + pstrcpy(server_path, get_home_dir(user_name)); + +#if (defined(HAVE_NETGROUP) && defined (WITH_AUTOMOUNT)) + + if (lp_nis_home_map()) + { + char *home_path_start; + char *automount_value = automount_lookup(user_name); + home_path_start = strchr(automount_value,':'); + if (home_path_start != NULL) + { + DEBUG(5, ("NIS lookup succeeded. Home path is: %s\n", + home_path_start?(home_path_start+1):"")); + pstrcpy(server_path, home_path_start+1); + } + } +#endif + + DEBUG(4,("Home server path: %s\n", server_path)); + + return server_path; +} + + +/******************************************************************* +sub strings with useful parameters +Rewritten by Stefaan A Eeckels and +Paul Rippin +********************************************************************/ +void standard_sub_basic(char *str) +{ + char *s, *p; + char pidstr[10]; + struct passwd *pass; + char *username = sam_logon_in_ssb ? samlogon_user : sesssetup_user; + + for (s = str ; s && *s && (p = strchr(s,'%')); s = p ) + { + switch (*(p+1)) + { + case 'G' : + { + if ((pass = Get_Pwnam(username,False))!=NULL) + { + string_sub(p,"%G",gidtoname(pass->pw_gid)); + } + else + { + p += 2; + } + break; + } + case 'N' : string_sub(p,"%N", automount_server(username)); break; + case 'I' : string_sub(p,"%I", client_addr(Client)); break; + case 'L' : string_sub(p,"%L", local_machine); break; + case 'M' : string_sub(p,"%M", client_name(Client)); break; + case 'R' : string_sub(p,"%R", remote_proto); break; + case 'T' : string_sub(p,"%T", timestring()); break; + case 'U' : string_sub(p,"%U", username); break; + case 'a' : string_sub(p,"%a", remote_arch); break; + case 'd' : + { + slprintf(pidstr,sizeof(pidstr) - 1, "%d",(int)getpid()); + string_sub(p,"%d", pidstr); + break; + } + case 'h' : string_sub(p,"%h", myhostname); break; + case 'm' : string_sub(p,"%m", remote_machine); break; + case 'v' : string_sub(p,"%v", VERSION); break; + case '$' : /* Expand environment variables */ + { + /* Contributed by Branko Cibej */ + fstring envname; + char *envval; + char *q, *r; + int copylen; + + if (*(p+2) != '(') + { + p+=2; + break; + } + if ((q = strchr(p,')')) == NULL) + { + DEBUG(0,("standard_sub_basic: Unterminated environment \ + variable [%s]\n", p)); + p+=2; + break; + } + + r = p+3; + copylen = MIN((q-r),(sizeof(envname)-1)); + strncpy(envname,r,copylen); + envname[copylen] = '\0'; + + if ((envval = getenv(envname)) == NULL) + { + DEBUG(0,("standard_sub_basic: Environment variable [%s] not set\n", + envname)); + p+=2; + break; + } + + copylen = MIN((q+1-p),(sizeof(envname)-1)); + strncpy(envname,p,copylen); + envname[copylen] = '\0'; + string_sub(p,envname,envval); + break; + } + case '\0': p++; break; /* don't run off end if last character is % */ + default : p+=2; break; + } + } + return; +} + +/******************************************************************* +are two IPs on the same subnet? +********************************************************************/ +BOOL same_net(struct in_addr ip1,struct in_addr ip2,struct in_addr mask) +{ + uint32 net1,net2,nmask; + + nmask = ntohl(mask.s_addr); + net1 = ntohl(ip1.s_addr); + net2 = ntohl(ip2.s_addr); + + return((net1 & nmask) == (net2 & nmask)); } @@ -3540,11 +4332,20 @@ struct hostent *Get_Hostbyname(char *name) exit(0); } + + /* + * This next test is redundent and causes some systems (with + * broken isalnum() calls) problems. + * JRA. + */ + +#if 0 if (!isalnum(*name2)) { free(name2); return(NULL); } +#endif /* 0 */ ret = sys_gethostbyname(name2); if (ret != NULL) @@ -3582,29 +4383,7 @@ check if a process exists. Does this work on all unixes? ****************************************************************************/ BOOL process_exists(int pid) { -#ifdef LINUX - fstring s; - sprintf(s,"/proc/%d",pid); - return(directory_exist(s,NULL)); -#else - { - static BOOL tested=False; - static BOOL ok=False; - fstring s; - if (!tested) { - tested = True; - sprintf(s,"/proc/%05d",(int)getpid()); - ok = file_exist(s,NULL); - } - if (ok) { - sprintf(s,"/proc/%05d",pid); - return(file_exist(s,NULL)); - } - } - - /* CGH 8/16/96 - added ESRCH test */ - return(pid == getpid() || kill(pid,0) == 0 || errno != ESRCH); -#endif + return(kill(pid,0) == 0 || errno != ESRCH); } @@ -3616,7 +4395,7 @@ char *uidtoname(int uid) static char name[40]; struct passwd *pass = getpwuid(uid); if (pass) return(pass->pw_name); - sprintf(name,"%d",uid); + slprintf(name, sizeof(name) - 1, "%d",uid); return(name); } @@ -3625,31 +4404,11 @@ turn a gid into a group name ********************************************************************/ char *gidtoname(int gid) { - static char name[40]; - struct group *grp = getgrgid(gid); - if (grp) return(grp->gr_name); - sprintf(name,"%d",gid); - return(name); -} - -/******************************************************************* -block sigs -********************************************************************/ -void BlockSignals(BOOL block,int signum) -{ -#ifdef USE_SIGBLOCK - int block_mask = sigmask(signum); - static int oldmask = 0; - if (block) - oldmask = sigblock(block_mask); - else - sigsetmask(oldmask); -#elif defined(USE_SIGPROCMASK) - sigset_t set; - sigemptyset(&set); - sigaddset(&set,signum); - sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL); -#endif + static char name[40]; + struct group *grp = getgrgid(gid); + if (grp) return(grp->gr_name); + slprintf(name,sizeof(name) - 1, "%d",gid); + return(name); } #if AJT @@ -3658,15 +4417,10 @@ my own panic function - not suitable for general use ********************************************************************/ void ajt_panic(void) { - system("/usr/bin/X11/xedit -display ljus:0 /tmp/ERROR_FAULT"); + system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT"); } #endif -#ifdef USE_DIRECT -#define DIRECT direct -#else -#define DIRECT dirent -#endif /******************************************************************* a readdir wrapper which just returns the file name @@ -3674,67 +4428,57 @@ also return the inode number if requested ********************************************************************/ char *readdirname(void *p) { - struct DIRECT *ptr; - char *dname; + struct dirent *ptr; + char *dname; - if (!p) return(NULL); + if (!p) return(NULL); - ptr = (struct DIRECT *)readdir(p); - if (!ptr) return(NULL); + ptr = (struct dirent *)readdir(p); + if (!ptr) return(NULL); - dname = ptr->d_name; + dname = ptr->d_name; #ifdef NEXT2 - if (telldir(p) < 0) return(NULL); + if (telldir(p) < 0) return(NULL); #endif -#ifdef SUNOS5 - /* this handles a broken compiler setup, causing a mixture - of BSD and SYSV headers and libraries */ - { - static BOOL broken_readdir = False; - if (!broken_readdir && !(*(dname)) && strequal("..",dname-2)) - { - DEBUG(0,("Your readdir() is broken. You have somehow mixed SYSV and BSD headers and libraries\n")); - broken_readdir = True; - } - if (broken_readdir) - dname = dname - 2; - } +#ifdef HAVE_BROKEN_READDIR + /* using /usr/ucb/cc is BAD */ + dname = dname - 2; #endif - { - static pstring buf; - pstrcpy(buf, dname); - unix_to_dos(buf, True); - dname = buf; - } + { + static pstring buf; + memcpy(buf, dname, NAMLEN(ptr)+1); + unix_to_dos(buf, True); + dname = buf; + } - return(dname); + return(dname); } -/* - * Utility function used to decide if the last component - * of a path matches a (possibly wildcarded) entry in a namelist. - */ +/******************************************************************* + Utility function used to decide if the last component + of a path matches a (possibly wildcarded) entry in a namelist. +********************************************************************/ BOOL is_in_path(char *name, name_compare_entry *namelist) { pstring last_component; char *p; - DEBUG(5, ("is_in_path: %s\n", name)); + DEBUG(8, ("is_in_path: %s\n", name)); /* if we have no list it's obviously not in the path */ if((namelist == NULL ) || ((namelist != NULL) && (namelist[0].name == NULL))) - { - DEBUG(5,("is_in_path: no name list.\n")); + { + DEBUG(8,("is_in_path: no name list.\n")); return False; -} + } /* Get the last component of the unix name. */ p = strrchr(name, '/'); - strncpy(last_component, p ? p : name, sizeof(last_component)-1); + strncpy(last_component, p ? ++p : name, sizeof(last_component)-1); last_component[sizeof(last_component)-1] = '\0'; for(; namelist->name != NULL; namelist++) @@ -3744,7 +4488,7 @@ BOOL is_in_path(char *name, name_compare_entry *namelist) /* look for a wildcard match. */ if (mask_match(last_component, namelist->name, case_sensitive, False)) { - DEBUG(5,("is_in_path: mask match succeeded\n")); + DEBUG(8,("is_in_path: mask match succeeded\n")); return True; } } @@ -3753,29 +4497,29 @@ BOOL is_in_path(char *name, name_compare_entry *namelist) if((case_sensitive && (strcmp(last_component, namelist->name) == 0))|| (!case_sensitive && (StrCaseCmp(last_component, namelist->name) == 0))) { - DEBUG(5,("is_in_path: match succeeded\n")); + DEBUG(8,("is_in_path: match succeeded\n")); return True; } } } - DEBUG(5,("is_in_path: match not found\n")); + DEBUG(8,("is_in_path: match not found\n")); return False; } -/* - * Strip a '/' separated list into an array of - * name_compare_enties structures suitable for - * passing to is_in_path(). We do this for - * speed so we can pre-parse all the names in the list - * and don't do it for each call to is_in_path(). - * namelist is modified here and is assumed to be - * a copy owned by the caller. - * We also check if the entry contains a wildcard to - * remove a potentially expensive call to mask_match - * if possible. - */ - +/******************************************************************* + Strip a '/' separated list into an array of + name_compare_enties structures suitable for + passing to is_in_path(). We do this for + speed so we can pre-parse all the names in the list + and don't do it for each call to is_in_path(). + namelist is modified here and is assumed to be + a copy owned by the caller. + We also check if the entry contains a wildcard to + remove a potentially expensive call to mask_match + if possible. +********************************************************************/ + void set_namearray(name_compare_entry **ppname_array, char *namelist) { char *name_end; @@ -3916,7 +4660,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) #endif - DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); + DEBUG(8,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); lock.l_type = type; lock.l_whence = SEEK_SET; @@ -3964,7 +4708,7 @@ BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) } /* everything went OK */ - DEBUG(5,("Lock call successful\n")); + DEBUG(8,("Lock call successful\n")); return(True); #else @@ -4032,23 +4776,23 @@ void set_remote_arch(enum remote_arch_types type) switch( type ) { case RA_WFWG: - strcpy(remote_arch, "WfWg"); + fstrcpy(remote_arch, "WfWg"); return; case RA_OS2: - strcpy(remote_arch, "OS2"); + fstrcpy(remote_arch, "OS2"); return; case RA_WIN95: - strcpy(remote_arch, "Win95"); + fstrcpy(remote_arch, "Win95"); return; case RA_WINNT: - strcpy(remote_arch, "WinNT"); + fstrcpy(remote_arch, "WinNT"); return; case RA_SAMBA: - strcpy(remote_arch,"Samba"); + fstrcpy(remote_arch,"Samba"); return; default: ra_type = RA_UNKNOWN; - strcpy(remote_arch, "UNKNOWN"); + fstrcpy(remote_arch, "UNKNOWN"); break; } } @@ -4056,57 +4800,403 @@ void set_remote_arch(enum remote_arch_types type) /******************************************************************* Get the remote_arch type. ********************************************************************/ -enum remote_arch_types get_remote_arch() +enum remote_arch_types get_remote_arch(void) { return ra_type; } + +/******************************************************************* +skip past some unicode strings in a buffer +********************************************************************/ +char *skip_unicode_string(char *buf,int n) +{ + while (n--) + { + while (*buf) + buf += 2; + buf += 2; + } + return(buf); +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistrn2(uint16 *buf, int len) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + DEBUG(10, ("unistrn2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2 && len > 0; len--, p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; +} + /******************************************************************* -safe string copy into a fstring +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings ********************************************************************/ -void fstrcpy(char *dest, char *src) +#define MAXUNI 1024 +char *unistr2(uint16 *buf) { - int maxlength = sizeof(fstring) - 1; + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + DEBUG(10, ("unistr2: ")); + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf++) + { + DEBUG(10, ("%4x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + + *p = 0; + return lbuf; +} + +/******************************************************************* +create a null-terminated unicode string from a null-terminated ascii string. +return number of unicode chars copied, excluding the null character. + +only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +int struni2(uint16 *p, char *buf) +{ + int len = 0; + + if (p == NULL) return 0; + + DEBUG(10, ("struni2: ")); + + if (buf != NULL) + { + for (; *buf && len < MAXUNI-2; len++, p++, buf++) + { + DEBUG(10, ("%2x ", *buf)); + *p = *buf; + } + + DEBUG(10,("\n")); + } + + *p = 0; + + return len; +} + +/******************************************************************* +Return a ascii version of a unicode string +Hack alert: uses fixed buffer(s) and only handles ascii strings +********************************************************************/ +#define MAXUNI 1024 +char *unistr(char *buf) +{ + static char lbufs[8][MAXUNI]; + static int nexti; + char *lbuf = lbufs[nexti]; + char *p; + + nexti = (nexti+1)%8; + + for (p = lbuf; *buf && p-lbuf < MAXUNI-2; p++, buf += 2) + { + *p = *buf; + } + *p = 0; + return lbuf; +} + +/******************************************************************* +strncpy for unicode strings +********************************************************************/ +int unistrncpy(char *dst, char *src, int len) +{ + int num_wchars = 0; + + while (*src && len > 0) + { + *dst++ = *src++; + *dst++ = *src++; + len--; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; + + return num_wchars; +} + + +/******************************************************************* +strcpy for unicode strings. returns length (in num of wide chars) +********************************************************************/ +int unistrcpy(char *dst, char *src) +{ + int num_wchars = 0; + + while (*src) + { + *dst++ = *src++; + *dst++ = *src++; + num_wchars++; + } + *dst++ = 0; + *dst++ = 0; + + return num_wchars; +} + +/******************************************************************* +safe string copy into a known length string. maxlength does not +include the terminating zero. +********************************************************************/ +char *safe_strcpy(char *dest, char *src, int maxlength) +{ + int len; + if (!dest) { - DEBUG(0,("ERROR: NULL dest in fstrcpy\n")); - return; + DEBUG(0,("ERROR: NULL dest in safe_strcpy\n")); + return NULL; } if (!src) { *dest = 0; - return; + return dest; } + + len = strlen(src); + + if (len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcpy [%.50s]\n", + len-maxlength, src)); + len = maxlength; + } - while (maxlength-- && *src) - *dest++ = *src++; - *dest = 0; - if (*src) { - DEBUG(0,("ERROR: string overflow by %d in fstrcpy\n", - strlen(src))); - } -} + memcpy(dest, src, len); + dest[len] = 0; + return dest; +} /******************************************************************* -safe string copy into a pstring +safe string cat into a string. maxlength does not +include the terminating zero. ********************************************************************/ -void pstrcpy(char *dest, char *src) +char *safe_strcat(char *dest, char *src, int maxlength) { - int maxlength = sizeof(pstring) - 1; + int src_len, dest_len; + if (!dest) { - DEBUG(0,("ERROR: NULL dest in pstrcpy\n")); - return; + DEBUG(0,("ERROR: NULL dest in safe_strcat\n")); + return NULL; } - + if (!src) { - *dest = 0; - return; + return dest; + } + + src_len = strlen(src); + dest_len = strlen(dest); + + if (src_len + dest_len > maxlength) { + DEBUG(0,("ERROR: string overflow by %d in safe_strcat [%.50s]\n", + src_len + dest_len - maxlength, src)); + src_len = maxlength - dest_len; } - - while (maxlength-- && *src) - *dest++ = *src++; - *dest = 0; - if (*src) { - DEBUG(0,("ERROR: string overflow by %d in pstrcpy\n", - strlen(src))); + + memcpy(&dest[dest_len], src, src_len); + dest[dest_len + src_len] = 0; + return dest; +} + +/******************************************************************* +align a pointer to a multiple of 4 bytes +********************************************************************/ +char *align4(char *q, char *base) +{ + if ((q - base) & 3) + { + q += 4 - ((q - base) & 3); + } + return q; +} + +/******************************************************************* +align a pointer to a multiple of 2 bytes +********************************************************************/ +char *align2(char *q, char *base) +{ + if ((q - base) & 1) + { + q++; + } + return q; +} + +/******************************************************************* +align a pointer to a multiple of align_offset bytes. looks like it +will work for offsets of 0, 2 and 4... +********************************************************************/ +char *align_offset(char *q, char *base, int align_offset_len) +{ + int mod = ((q - base) & (align_offset_len-1)); + if (align_offset_len != 0 && mod != 0) + { + q += align_offset_len - mod; + } + return q; +} + +void print_asc(int level, unsigned char *buf,int len) +{ + int i; + for (i=0;i8) DEBUG(level,(" ")); + while (n--) DEBUG(level,(" ")); + + n = MIN(8,i%16); + print_asc(level,&buf[i-(i%16)],n); DEBUG(level,(" ")); + n = (i%16) - n; + if (n>0) print_asc(level,&buf[i-n],n); + DEBUG(level,("\n")); + } +} + +char *tab_depth(int depth) +{ + static pstring spaces; + memset(spaces, ' ', depth * 4); + spaces[depth * 4] = 0; + return spaces; +} + +/***************************************************************** + Convert a SID to an ascii string. +*****************************************************************/ + +char *sid_to_string(pstring sidstr_out, DOM_SID *sid) +{ + char subauth[16]; + int i; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia = (sid->id_auth[5]) + + (sid->id_auth[4] << 8 ) + + (sid->id_auth[3] << 16) + + (sid->id_auth[2] << 24); + + slprintf(sidstr_out, sizeof(pstring) - 1, "S-%d-%d", sid->sid_rev_num, ia); + + for (i = 0; i < sid->num_auths; i++) + { + slprintf(subauth, sizeof(subauth)-1, "-%d", sid->sub_auths[i]); + pstrcat(sidstr_out, subauth); + } + + DEBUG(7,("sid_to_string returning %s\n", sidstr_out)); + return sidstr_out; +} + +/***************************************************************** + Convert a string to a SID. Returns True on success, False on fail. +*****************************************************************/ + +BOOL string_to_sid(DOM_SID *sidout, char *sidstr) +{ + pstring tok; + char *p = sidstr; + /* BIG NOTE: this function only does SIDS where the identauth is not >= 2^32 */ + uint32 ia; + + memset((char *)sidout, '\0', sizeof(DOM_SID)); + + if(StrnCaseCmp( sidstr, "S-", 2)) { + DEBUG(0,("string_to_sid: Sid %s does not start with 'S-'.\n", sidstr)); + return False; + } + + p += 2; + if(!next_token(&p, tok, "-")) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* Get the revision number. */ + sidout->sid_rev_num = atoi(tok); + + if(!next_token(&p, tok, "-")) { + DEBUG(0,("string_to_sid: Sid %s is not in a valid format.\n", sidstr)); + return False; + } + + /* identauth in decimal should be < 2^32 */ + ia = atoi(tok); + + /* NOTE - the ia value is in big-endian format. */ + sidout->id_auth[0] = 0; + sidout->id_auth[1] = 0; + sidout->id_auth[2] = (ia & 0xff000000) >> 24; + sidout->id_auth[3] = (ia & 0x00ff0000) >> 16; + sidout->id_auth[4] = (ia & 0x0000ff00) >> 8; + sidout->id_auth[5] = (ia & 0x000000ff); + + sidout->num_auths = 0; + + while(next_token(&p, tok, "-") && sidout->num_auths < MAXSUBAUTHS) { + /* + * NOTE - the subauths are in native machine-endian format. They + * are converted to little-endian when linearized onto the wire. + */ + sidout->sub_auths[sidout->num_auths++] = atoi(tok); + } + + DEBUG(7,("string_to_sid: converted SID %s ok\n", sidstr)); + + return True; +}