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