1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * lssmb.c: Contains all code specific to the MS-NET file server. 33 * Undef SMBSERVER to remove SMB support. 34 */ 35 36 37 #include <stdio.h> 38 #include <string.h> 39 #include <sys/param.h> 40 #include <sys/tiuser.h> 41 42 #include "lsparam.h" 43 #include "lssmbmsg.h" 44 #include "lsdbf.h" 45 46 47 #ifdef SMBSERVER 48 49 50 /* 51 * Dlevel - Debug level for DEBUG((level, ... ) type calls 52 * Msnet - Who is logging this message (the SMB code is) 53 */ 54 55 #define Dlevel 3 56 #define Msnet "SMB parser:" 57 58 extern char *malloc(); 59 char *bytes_to_ascii(); 60 void getword(char *addr, short *w); 61 62 /* 63 * In the event of an error, it may be necessary to send a response to 64 * the remote node before closing the virtual circuit. The following 65 * is the return message that should be sent. (Initially, I am not 66 * bothering to send the response message; I am assuming that the 67 * MS-NET client will be able to figure out that things went wrong, but 68 * we may find that is not the case. 69 */ 70 71 static unsigned char errbuf[] = { 72 /* NegProt Return */ 0xff, 'S', 'M', 'B', 0x72, 73 /* ERRSRV */ 0x2, 74 0, 75 /* SMBerror */ 0x1, 0, 76 0, 77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78 0, 0, 79 0, 0, 80 0, 0, 0, 0, 81 /* wcnt == 1 */ 1, 82 /* no dialects */ 0xff, 0xff, 83 0, 0 84 }; 85 86 87 /* 88 * s m b s e r v i c e 89 * 90 * Function called by listener process when it receives a connect 91 * request from a node that wants to talk Microsoft's MS-NET Core 92 * Protocol...the functions gets called after the listener forks. 93 */ 94 95 void 96 smbservice(bp, bufsize, argv) 97 char *bp; /* pointer to message buffer */ 98 int bufsize; /* size of message */ 99 char **argv; /* server arguments */ 100 { 101 char *server = *argv; /* path of server */ 102 char logbuf[256]; 103 char **args; 104 int i, m_size; 105 int twos, nulls; 106 char *p, *q; 107 short size; 108 109 /* 110 * Is this really a correct negotiate protocol message? 111 */ 112 113 if (*(bp+FSP_COM) != FSPnegprot){ 114 sprintf(logbuf, "%s: Bad Command Code, 0x%x", 115 Msnet, *(bp+FSP_COM)); 116 goto badexit; 117 } 118 119 /* 120 * Are there exactly 0 argument words in the message? 121 */ 122 123 if (*(bp+FSP_WCNT) != 0){ 124 sprintf(logbuf, "%s: Incorrect # of Parameter Words, 0x%x", 125 Msnet, *(bp+FSP_WCNT)); 126 goto badexit; 127 } 128 129 /* 130 * get the size of the data in the message 131 */ 132 133 p = bp + FSP_PARMS; 134 getword(p, &size); 135 136 /* 137 * make sure the data is valid; it should have a series of 138 * "dialect" strings, which are of the form [02 string 00]. 139 * if(twos == nulls) then the data is well formed, else something 140 * is wrong. 141 */ 142 143 twos = nulls = 0; 144 p += 2; 145 for(q = p; q < p + size; ++q){ 146 if(*q == '\0') 147 nulls++; 148 else if(*q == 02) 149 twos++; 150 } 151 152 if(twos != nulls){ 153 sprintf(logbuf, "%s: Bad Data Format, twos=%d, nulls=%d", 154 Msnet, twos, nulls); 155 goto badexit; 156 } 157 158 /* 159 * Count the number of arguments that were passed 160 * to me by the listener... 161 */ 162 163 for(i=0, args=argv; *args; ++args, ++i) 164 ; 165 166 /* 167 * There are a few kinds of arguments that I will pass to the server: 168 * 169 * -D<string> - means "the client speaks this dialect . . ." 170 * there me be more than one of these, if the client 171 * is able to speak multiple dialects. 172 * 173 * Any arguments passed to me by the listener will be passed along 174 * as is . . . 175 * 176 * Allocate an array of "char *"s that will let me point to all 177 * of the following: 178 * 1. As many -D options as are needed (the exact number is 179 * contained in the variable "twos"), 180 * 2. One -A option for the single logical name 181 * of the client, 182 * 3. As many positions as are needed to pass along the arguments 183 * passed to me by the listener (variable "i"), 184 * 4. The name of the Server executable file (always arg[0]), and 185 * 5. "Ascii-ized" version of input message as last arg. 186 * 6. A NULL terminator. 187 */ 188 189 m_size = sizeof(char *) * (twos + i + 4); 190 if((args = (char **)malloc((unsigned)m_size)) == 0){ 191 sprintf(logbuf, "%s: Can't malloc arg space, %d bytes", 192 Msnet, m_size); 193 goto badexit; 194 } 195 196 /* 197 * put together the first argument to exec(2) which should be 198 * the full pathname of the executable server file. 199 */ 200 201 args[0] = server; 202 203 /* 204 * Send dialect strings down, in order of preference 205 */ 206 207 for(i=1, q=p; q < p + size; ++i, ++q){ 208 q = strchr(q, 02); /* find start of string */ 209 210 m_size = strlen(++q) + 1 + 2; 211 if((args[i] = malloc((unsigned)m_size)) == 0){ 212 sprintf(logbuf, 213 "%s: Can't malloc Server Path buf, %d bytes", 214 Msnet, m_size); 215 goto badexit; 216 } 217 218 strcpy(args[i], "-D"); 219 strcat(args[i], q); /* put -Ddialect\0 in arglist */ 220 q = strchr(q, '\0'); /* find end of string */ 221 } 222 223 /* 224 * Add in arguments that were passed to me by the listener 225 * first arg is server path, so we ignore that. 226 */ 227 228 for( ++argv; *argv; ++argv, ++i) 229 args[i] = *argv; 230 231 /* 232 * add ascii-ized version of message 233 */ 234 235 args[i++] = bytes_to_ascii(bp, bufsize); 236 237 /* 238 * NULL terminate the list 239 */ 240 241 args[i] = NULL; 242 243 exec_cmd((dbf_t *)0, args); 244 return; /* error logged in start_server */ 245 246 badexit: 247 logmessage(logbuf); 248 } 249 250 251 /* 252 * g e t w o r d 253 * 254 * move a word from an arbitrary position in a character buffer, into 255 * a short, and flip the bytes. 256 * (NOTE that word is a 16-bit iapx-286 word). 257 */ 258 259 void 260 getword(char *addr, short *w) 261 { 262 lobyte(*w) = *addr++; 263 hibyte(*w) = *addr; 264 } 265 266 /* b y t e s _ t o _ a s c i i 267 * Routine to convert a binary array to a printable sequence of 268 * characters. For example, if the input to this routine were: 269 * 270 * inbuf = "012", and n = 3 271 * 272 * then the output would be a pointer to the string: 273 * 274 * "303132" 275 * 276 * No assumption is made about NULL terminators on input, because 277 * it is probably binary, and not a string. 278 */ 279 280 281 char * 282 bytes_to_ascii(inbuf, n) 283 char *inbuf; /* initialized buffer of binary data */ 284 int n; /* size of input buffer */ 285 { 286 char *outbuf; /* return string */ 287 char *p; /* scratch pointer */ 288 int i; /* scratch variable */ 289 290 /* malloc 2x space for output plus one for NULL */ 291 if (outbuf = malloc(n * 2 + 1)) { 292 /* Fill in output buffer, with 2 character, capitalized hex. */ 293 for (i = 0, p = outbuf; i < n; ++inbuf, p += 2, ++i) { 294 sprintf(p, "%2.2X", *inbuf); 295 } 296 return(outbuf); 297 } 298 else 299 return(NULL); 300 } 301 302 303 304 #else 305 306 void 307 smbservice(bp, size, argv) 308 char *bp; /* pointer to message buffer */ 309 int size; /* size of message */ 310 char **argv; /* server arguments */ 311 { 312 logmessage("SMB service NOT supported"); 313 } 314 315 #endif /* SMBSERVICE */ 316