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