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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Functions to open and close named pipes. These functions are 30 * described in the CIFS 1.0 Protocol Specification (December 19, 1997). 31 */ 32 33 #include <alloca.h> 34 #include <pthread.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <syslog.h> 38 #include <synch.h> 39 40 #include <smbsrv/libsmbrdr.h> 41 #include <smbsrv/ntstatus.h> 42 #include <smbrdr.h> 43 44 static int smbrdr_close(struct sdb_ofile *); 45 static DWORD smbrdr_ntcreatex(struct sdb_ofile *); 46 static struct sdb_ofile *smbrdr_ofile_alloc(struct sdb_netuse *, char *); 47 48 static void 49 smbrdr_ofile_clear(struct sdb_ofile *ofile) 50 { 51 bzero(ofile, sizeof (struct sdb_ofile) - sizeof (mutex_t)); 52 } 53 54 static void 55 smbrdr_ofile_free(struct sdb_ofile *ofile) 56 { 57 smbrdr_ofile_clear(ofile); 58 (void) mutex_unlock(&ofile->mtx); 59 } 60 61 62 /* 63 * The ofile table. 64 */ 65 static struct sdb_ofile ofile_table[N_OFILE_TABLE]; 66 67 static int mlsvc_pipe_recon_wait = 50; 68 static int mlsvc_pipe_recon_tries = 3; 69 70 71 /* 72 * mlsvc_open_pipe 73 * 74 * Open an RPC pipe on hostname. On success, return the fid. Otherwise 75 * returns a -ve error code. 76 */ 77 int 78 mlsvc_open_pipe(char *hostname, char *domain, char *username, char *pipename) 79 { 80 struct sdb_netuse *netuse; 81 struct sdb_ofile *ofile; 82 unsigned short tid; 83 DWORD status; 84 int retry; 85 struct timespec st; 86 87 tid = smbrdr_tree_connect(hostname, username, "IPC$"); 88 if (tid == 0) { 89 syslog(LOG_DEBUG, "smbrdr: (open) %s %s %s %s %s", 90 hostname, domain, username, pipename, 91 xlate_nt_status(NT_STATUS_UNEXPECTED_NETWORK_ERROR)); 92 return (-1); 93 } 94 95 netuse = smbrdr_netuse_get(tid); 96 if (netuse == NULL) { 97 syslog(LOG_DEBUG, "smbrdr: (open) %s %s %s %s %s", 98 hostname, domain, username, pipename, 99 xlate_nt_status(NT_STATUS_CONNECTION_INVALID)); 100 return (-1); 101 } 102 103 if ((ofile = smbrdr_ofile_alloc(netuse, pipename)) == 0) { 104 syslog(LOG_DEBUG, "smbrdr: (open) %s %s %s %s %s", 105 hostname, domain, username, pipename, 106 xlate_nt_status(NT_STATUS_INSUFFICIENT_RESOURCES)); 107 smbrdr_netuse_put(netuse); 108 return (-1); 109 } 110 111 status = NT_STATUS_OPEN_FAILED; 112 113 for (retry = 0; retry < mlsvc_pipe_recon_tries; retry++) { 114 status = smbrdr_ntcreatex(ofile); 115 116 switch (status) { 117 case NT_STATUS_SUCCESS: 118 (void) mutex_unlock(&ofile->mtx); 119 smbrdr_netuse_put(netuse); 120 return (ofile->fid); 121 122 case NT_STATUS_PIPE_NOT_AVAILABLE: 123 case NT_STATUS_PIPE_BUSY: 124 /* 125 * The server might return this error if it is 126 * temporarily busy or unable to create a pipe. 127 * We wait here before trying again to see if 128 * the pipe becomes available. 129 */ 130 st.tv_sec = 0; 131 st.tv_nsec = mlsvc_pipe_recon_wait * 1000000; 132 (void) nanosleep(&st, 0); 133 break; 134 135 default: 136 /* 137 * Something else went wrong: no more retries. 138 */ 139 retry = mlsvc_pipe_recon_tries; 140 break; 141 } 142 } 143 144 syslog(LOG_DEBUG, "smbrdr: (open) %s %s %s %s %s", 145 hostname, domain, username, pipename, 146 xlate_nt_status(status)); 147 smbrdr_ofile_free(ofile); 148 smbrdr_netuse_put(netuse); 149 return (-1); 150 } 151 152 /* 153 * mlsvc_close_pipe 154 * 155 * Close the named pipe represented by fid. 156 */ 157 int 158 mlsvc_close_pipe(int fid) 159 { 160 struct sdb_ofile *ofile; 161 unsigned short tid; 162 int rc; 163 164 if ((ofile = smbrdr_ofile_get(fid)) == NULL) 165 return (-1); 166 167 tid = ofile->tid; 168 rc = smbrdr_close(ofile); 169 smbrdr_ofile_put(ofile); 170 171 if (rc == 0) 172 (void) smbrdr_tree_disconnect(tid); 173 174 return (rc); 175 } 176 177 /* 178 * smbrdr_ofile_put 179 * 180 * Unlock given ofile structure. 181 */ 182 void 183 smbrdr_ofile_put(struct sdb_ofile *ofile) 184 { 185 if (ofile) 186 (void) mutex_unlock(&ofile->mtx); 187 } 188 189 /* 190 * smbrdr_ofile_get 191 * 192 * Locate the ofile for the specified fid. Just to be safe, ensure that 193 * the netuse pointer is valid. Return a pointer to the ofile structure. 194 * Return a null pointer if a valid ofile cannot be found. 195 */ 196 struct sdb_ofile * 197 smbrdr_ofile_get(int fid) 198 { 199 struct sdb_session *session; 200 struct sdb_netuse *netuse; 201 struct sdb_ofile *ofile; 202 int i; 203 204 for (i = 0; i < N_OFILE_TABLE; ++i) { 205 ofile = &ofile_table[i]; 206 207 (void) mutex_lock(&ofile->mtx); 208 209 if (ofile->fid == fid) { 210 session = ofile->session; 211 netuse = ofile->netuse; 212 213 /* 214 * status check: 215 * make sure all the structures are in the right state 216 */ 217 if (session && netuse && 218 (ofile->state == SDB_FSTATE_OPEN) && 219 (netuse->state == SDB_NSTATE_CONNECTED) && 220 (session->logon.state == SDB_LSTATE_SETUP) && 221 (session->state == SDB_SSTATE_NEGOTIATED)) { 222 /* sanity check */ 223 if ((ofile->sid == session->sid) && 224 (ofile->uid == session->logon.uid) && 225 (ofile->tid == netuse->tid)) { 226 return (ofile); 227 } else { 228 /* invalid structure */ 229 smbrdr_ofile_clear(ofile); 230 } 231 } 232 } 233 234 (void) mutex_unlock(&ofile->mtx); 235 } 236 237 return (NULL); 238 } 239 240 /* 241 * smbrdr_ofile_end_of_share 242 * 243 * This function can be used when closing a share to ensure that all 244 * ofiles resources are released. Don't call mlsvc_close_pipe because 245 * that will call mlsvc_smb_tdcon and we don't know what state 246 * the share is in. The server will probably close all files anyway. 247 * We are more interested in releasing the ofile resources. 248 */ 249 void 250 smbrdr_ofile_end_of_share(unsigned short tid) 251 { 252 struct sdb_ofile *ofile; 253 int i; 254 255 for (i = 0; i < N_OFILE_TABLE; ++i) { 256 ofile = &ofile_table[i]; 257 (void) mutex_lock(&ofile->mtx); 258 if (ofile->tid == tid) 259 (void) smbrdr_close(ofile); 260 (void) mutex_unlock(&ofile->mtx); 261 } 262 } 263 264 /* 265 * smbrdr_dump_ofiles 266 * 267 * Dump the open files table. 268 */ 269 void 270 smbrdr_dump_ofiles() 271 { 272 struct sdb_ofile *ofile; 273 struct sdb_netuse *netuse; 274 int i; 275 276 for (i = 0; i < N_OFILE_TABLE; ++i) { 277 ofile = &ofile_table[i]; 278 (void) mutex_lock(&ofile->mtx); 279 netuse = ofile->netuse; 280 281 if (netuse) { 282 syslog(LOG_DEBUG, "file[%d]: %s (fid=%d)", i, 283 ofile->path, ofile->fid); 284 syslog(LOG_DEBUG, 285 "file[%d]: session(%d), user(%d), tree(%d)", 286 i, netuse->session->sock, netuse->uid, 287 netuse->tid); 288 } 289 (void) mutex_unlock(&ofile->mtx); 290 } 291 } 292 293 /* 294 * Private Functions 295 */ 296 297 /* 298 * smbrdr_close 299 * 300 * Send SMBClose request for the given open file. 301 */ 302 static int 303 smbrdr_close(struct sdb_ofile *ofile) 304 { 305 struct sdb_session *session; 306 struct sdb_netuse *netuse; 307 struct sdb_logon *logon; 308 smbrdr_handle_t srh; 309 smb_hdr_t smb_hdr; 310 DWORD status; 311 int fid; 312 int rc; 313 314 if (ofile == NULL) 315 return (0); 316 317 ofile->state = SDB_FSTATE_CLOSING; 318 319 if ((session = ofile->session) == NULL) { 320 smbrdr_ofile_clear(ofile); 321 return (0); 322 } 323 324 if ((session->state != SDB_SSTATE_NEGOTIATED) && 325 (session->state != SDB_SSTATE_DISCONNECTING)) { 326 smbrdr_ofile_clear(ofile); 327 return (0); 328 } 329 330 fid = ofile->fid; 331 332 netuse = ofile->netuse; 333 logon = &session->logon; 334 335 status = smbrdr_request_init(&srh, SMB_COM_CLOSE, 336 session, logon, netuse); 337 338 if (status != NT_STATUS_SUCCESS) { 339 smbrdr_ofile_clear(ofile); 340 return (-1); 341 } 342 343 rc = smb_msgbuf_encode(&srh.srh_mbuf, "bwlw.", 3, fid, 0x00000000ul, 0); 344 if (rc <= 0) { 345 smbrdr_handle_free(&srh); 346 smbrdr_ofile_clear(ofile); 347 return (-1); 348 } 349 350 status = smbrdr_exchange(&srh, &smb_hdr, 0); 351 if (status != NT_STATUS_SUCCESS) 352 syslog(LOG_DEBUG, "smbrdr_close: %s", xlate_nt_status(status)); 353 354 smbrdr_handle_free(&srh); 355 smbrdr_ofile_clear(ofile); 356 return (0); 357 } 358 359 /* 360 * smbrdr_ofile_alloc 361 * 362 * Allocate an ofile for the specified name. File info is associated 363 * with a share so we need a valid share before calling this function. 364 * If a slot is already allocated to the specified file, a pointer to 365 * that slot is returned. Otherwise we allocate and initialize a new 366 * slot in the table. If the table is full, a null pointer will be 367 * returned. 368 */ 369 static struct sdb_ofile * 370 smbrdr_ofile_alloc(struct sdb_netuse *netuse, char *name) 371 { 372 struct sdb_ofile *ofile; 373 int i; 374 375 for (i = 0; i < N_OFILE_TABLE; ++i) { 376 ofile = &ofile_table[i]; 377 378 (void) mutex_lock(&ofile->mtx); 379 if (ofile->netuse == 0) { 380 381 ofile->session = netuse->session; 382 ofile->netuse = netuse; 383 ofile->sid = netuse->session->sid; 384 ofile->uid = netuse->session->logon.uid; 385 ofile->tid = netuse->tid; 386 ofile->fid = 0; 387 (void) strcpy(ofile->path, name); 388 ofile->state = SDB_FSTATE_INIT; 389 return (ofile); 390 } 391 392 (void) mutex_unlock(&ofile->mtx); 393 } 394 395 return (NULL); 396 } 397 398 /* 399 * smbrdr_ntcreatex 400 * 401 * This will do an SMB_COM_NT_CREATE_ANDX with lots of default values. 402 * All of the underlying session and share data should already be set 403 * up before we get here. If everything works we'll get a valid fid. 404 */ 405 static DWORD 406 smbrdr_ntcreatex(struct sdb_ofile *ofile) 407 { 408 struct sdb_logon *logon; 409 struct sdb_netuse *netuse; 410 struct sdb_session *sess; 411 smbrdr_handle_t srh; 412 smb_hdr_t smb_hdr; 413 smb_msgbuf_t *mb; 414 char *path; 415 unsigned path_len; 416 int data_bytes; 417 int rc; 418 unsigned short fid; 419 int null_size; 420 DWORD status; 421 422 netuse = ofile->netuse; 423 sess = netuse->session; 424 logon = &sess->logon; 425 426 /* 427 * If this was a general purpose interface, we should support 428 * full UNC semantics but we only use this for RPC over named 429 * pipes with well-known endpoints. 430 */ 431 path_len = strlen(ofile->path) + 2; 432 path = alloca(path_len); 433 434 if (ofile->path[0] != '\\') 435 (void) snprintf(path, path_len, "\\%s", ofile->path); 436 else 437 (void) strcpy(path, ofile->path); 438 439 if (sess->remote_caps & CAP_UNICODE) { 440 path_len = mts_wcequiv_strlen(path); 441 null_size = sizeof (mts_wchar_t); 442 } else { 443 path_len = strlen(path); 444 null_size = sizeof (char); 445 } 446 447 syslog(LOG_DEBUG, "smbrdr_ntcreatex: %d %s", path_len, path); 448 449 status = smbrdr_request_init(&srh, SMB_COM_NT_CREATE_ANDX, 450 sess, logon, netuse); 451 452 if (status != NT_STATUS_SUCCESS) { 453 syslog(LOG_DEBUG, "smbrdr_ntcreatex: %s", 454 xlate_nt_status(status)); 455 return (NT_STATUS_INVALID_PARAMETER_1); 456 } 457 458 mb = &srh.srh_mbuf; 459 460 data_bytes = path_len + null_size; 461 462 rc = smb_msgbuf_encode(mb, 463 "(wct)b (andx)b1.w (resv). (nlen)w (flg)l" 464 "(rdf)l (dacc)l (allo)q (efa)l (shr)l (cdisp)l (copt)l (impl)l" 465 "(secf)b (bcc)w (name)u", 466 24, /* smb_wct */ 467 0xff, /* AndXCommand (none) */ 468 0x0000, /* AndXOffset */ 469 path_len, /* Unicode NameLength */ 470 0x00000006ul, /* Flags (oplocks) */ 471 0, /* RootDirectoryFid */ 472 0x0002019Ful, /* DesiredAccess */ 473 0x0ull, /* AllocationSize */ 474 0x00000000ul, /* ExtFileAttributes */ 475 0x00000003ul, /* ShareAccess (RW) */ 476 0x00000001ul, /* CreateDisposition (OpenExisting) */ 477 0x00000000ul, /* CreateOptions */ 478 0x00000002ul, /* ImpersonationLevel */ 479 0x01u, /* SecurityFlags */ 480 data_bytes, /* smb_bcc */ 481 path); /* Name */ 482 483 if (rc <= 0) { 484 smbrdr_handle_free(&srh); 485 return (NT_STATUS_INVALID_PARAMETER_1); 486 } 487 488 status = smbrdr_exchange(&srh, &smb_hdr, 0); 489 if (status != NT_STATUS_SUCCESS) { 490 smbrdr_handle_free(&srh); 491 return (NT_SC_VALUE(status)); 492 } 493 494 rc = smb_msgbuf_decode(mb, "(wct). (andx)4. (opl)1. (fid)w", &fid); 495 if (rc <= 0) { 496 smbrdr_handle_free(&srh); 497 return (NT_STATUS_INVALID_PARAMETER_2); 498 } 499 500 ofile->fid = fid; 501 ofile->state = SDB_FSTATE_OPEN; 502 syslog(LOG_DEBUG, "SmbRdrNtCreate: fid=%d", ofile->fid); 503 smbrdr_handle_free(&srh); 504 return (NT_STATUS_SUCCESS); 505 } 506