ncp_mod.c revision 111815
1/* 2 * Copyright (c) 2003 Tim J. Robbins. 3 * Copyright (c) 1999, 2000, 2001 Boris Popov 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Boris Popov. 17 * 4. Neither the name of the author nor the names of any co-contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: head/sys/netncp/ncp_mod.c 111815 2003-03-03 12:15:54Z phk $ 34 */ 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/conf.h> 38#include <sys/proc.h> 39#include <sys/kernel.h> 40#include <sys/sysctl.h> 41#include <sys/malloc.h> 42#include <sys/uio.h> 43#include <sys/ioccom.h> 44 45#include <netncp/ncp.h> 46#include <netncp/ncp_conn.h> 47#include <netncp/ncp_subr.h> 48#include <netncp/ncp_ncp.h> 49#include <netncp/ncp_user.h> 50#include <netncp/ncp_rq.h> 51#include <netncp/ncp_nls.h> 52#include <netncp/ncpio.h> 53 54int ncp_version = NCP_VERSION; 55 56SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester"); 57SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, ""); 58 59MODULE_VERSION(ncp, 1); 60MODULE_DEPEND(ncp, libmchain, 1, 1, 1); 61 62static dev_t ncp_dev; 63 64static d_ioctl_t ncp_ioctl; 65 66static struct cdevsw ncp_cdevsw = { 67 .d_open = nullopen, 68 .d_close = nullclose, 69 .d_ioctl = ncp_ioctl, 70 .d_name = "ncp", 71 .d_maj = MAJOR_AUTO, 72}; 73 74static int ncp_conn_frag_rq(struct ncp_conn *, struct thread *, 75 struct ncp_conn_frag *); 76static int ncp_conn_handler(struct thread *, struct ncpioc_request *, 77 struct ncp_conn *, struct ncp_handle *); 78static int sncp_conn_scan(struct thread *, struct ncpioc_connscan *); 79static int sncp_connect(struct thread *, struct ncpioc_connect *); 80static int sncp_request(struct thread *, struct ncpioc_request *); 81 82static int 83ncp_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 84{ 85 86 switch (cmd) { 87 case NCPIOC_CONNECT: 88 return (sncp_connect(td, (struct ncpioc_connect *)data)); 89 case NCPIOC_CONNSCAN: 90 return (sncp_conn_scan(td, (struct ncpioc_connscan *)data)); 91 case NCPIOC_REQUEST: 92 return (sncp_request(td, (struct ncpioc_request *)data)); 93 } 94 return (EINVAL); 95} 96 97/* 98 * Attach to NCP server 99 */ 100 101static int 102sncp_connect(struct thread *td, struct ncpioc_connect *args) 103{ 104 int connHandle = 0, error; 105 struct ncp_conn *conn; 106 struct ncp_handle *handle; 107 struct ncp_conn_args li; 108 109 checkbad(copyin(args->ioc_li,&li,sizeof(li))); 110 /* XXX Should be useracc() */ 111 checkbad(copyout(&connHandle,args->ioc_connhandle, 112 sizeof(connHandle))); 113 li.password = li.user = NULL; 114 error = ncp_conn_getattached(&li, td, td->td_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn); 115 if (error) { 116 error = ncp_conn_alloc(&li, td, td->td_ucred, &conn); 117 if (error) 118 goto bad; 119 error = ncp_conn_reconnect(conn); 120 if (error) 121 ncp_conn_free(conn); 122 } 123 if (!error) { 124 error = ncp_conn_gethandle(conn, td, &handle); 125 copyout(&handle->nh_id, args->ioc_connhandle, 126 sizeof(args->ioc_connhandle)); 127 ncp_conn_unlock(conn,td); 128 } 129bad: 130 return error; 131} 132 133static int 134sncp_request(struct thread *td, struct ncpioc_request *args) 135{ 136 struct ncp_rq *rqp; 137 struct ncp_conn *conn; 138 struct ncp_handle *handle; 139 int error = 0, rqsize; 140 141 error = ncp_conn_findhandle(args->ioc_connhandle, td, &handle); 142 if (error) 143 return error; 144 conn = handle->nh_conn; 145 if (args->ioc_fn == NCP_CONN) 146 return ncp_conn_handler(td, args, conn, handle); 147 error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int)); 148 if (error) 149 return(error); 150 error = ncp_rq_alloc(args->ioc_fn, conn, td, td->td_ucred, &rqp); 151 if (error) 152 return error; 153 if (rqsize) { 154 error = mb_put_mem(&rqp->rq, (caddr_t)args->ioc_ncpbuf->packet, 155 rqsize, MB_MUSER); 156 if (error) 157 goto bad; 158 } 159 rqp->nr_flags |= NCPR_DONTFREEONERR; 160 error = ncp_request(rqp); 161 if (error == 0 && rqp->nr_rpsize) 162 error = md_get_mem(&rqp->rp, (caddr_t)args->ioc_ncpbuf->packet, 163 rqp->nr_rpsize, MB_MUSER); 164 copyout(&rqp->nr_cs, &args->ioc_ncpbuf->cs, sizeof(rqp->nr_cs)); 165 copyout(&rqp->nr_cc, &args->ioc_ncpbuf->cc, sizeof(rqp->nr_cc)); 166 copyout(&rqp->nr_rpsize, &args->ioc_ncpbuf->rpsize, sizeof(rqp->nr_rpsize)); 167bad: 168 ncp_rq_done(rqp); 169 return error; 170} 171 172static int 173ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password, 174 struct thread *td, struct ucred *cred) 175{ 176 int error; 177 178 if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid) 179 return EACCES; 180 conn->li.user = ncp_str_dup(user); 181 if (conn->li.user == NULL) 182 return ENOMEM; 183 conn->li.password = ncp_str_dup(password); 184 if (conn->li.password == NULL) { 185 error = ENOMEM; 186 goto bad; 187 } 188 ncp_str_upper(conn->li.user); 189 if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0) 190 ncp_str_upper(conn->li.password); 191 conn->li.objtype = objtype; 192 error = ncp_conn_login(conn, td, cred); 193 return error; 194bad: 195 if (conn->li.user) { 196 free(conn->li.user, M_NCPDATA); 197 conn->li.user = NULL; 198 } 199 if (conn->li.password) { 200 free(conn->li.password, M_NCPDATA); 201 conn->li.password = NULL; 202 } 203 return error; 204} 205 206static int 207ncp_conn_handler(struct thread *td, struct ncpioc_request *args, 208 struct ncp_conn *conn, struct ncp_handle *hp) 209{ 210 int error = 0, rqsize, subfn; 211 struct ucred *cred; 212 213 char *pdata; 214 215 cred = td->td_ucred; 216 error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int)); 217 if (error) 218 return(error); 219 error = 0; 220 pdata = args->ioc_ncpbuf->packet; 221 subfn = *(pdata++) & 0xff; 222 rqsize--; 223 switch (subfn) { 224 case NCP_CONN_READ: case NCP_CONN_WRITE: { 225 struct ncp_rw rwrq; 226 struct uio auio; 227 struct iovec iov; 228 229 if (rqsize != sizeof(rwrq)) 230 return (EBADRPC); 231 error = copyin(pdata,&rwrq,rqsize); 232 if (error) 233 return (error); 234 iov.iov_base = rwrq.nrw_base; 235 iov.iov_len = rwrq.nrw_cnt; 236 auio.uio_iov = &iov; 237 auio.uio_iovcnt = 1; 238 auio.uio_offset = rwrq.nrw_offset; 239 auio.uio_resid = rwrq.nrw_cnt; 240 auio.uio_segflg = UIO_USERSPACE; 241 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE; 242 auio.uio_td = td; 243 if (subfn == NCP_CONN_READ) 244 error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred); 245 else 246 error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred); 247 rwrq.nrw_cnt -= auio.uio_resid; 248 /*td->td_retval[0] = rwrq.nrw_cnt;*/ 249 break; 250 } /* case int_read/write */ 251 case NCP_CONN_SETFLAGS: { 252 u_int16_t mask, flags; 253 254 error = copyin(pdata,&mask, sizeof(mask)); 255 if (error) 256 return error; 257 pdata += sizeof(mask); 258 error = copyin(pdata,&flags,sizeof(flags)); 259 if (error) 260 return error; 261 error = ncp_conn_lock(conn, td, cred, NCPM_WRITE); 262 if (error) 263 return error; 264 if (mask & NCPFL_PERMANENT) { 265 conn->flags &= ~NCPFL_PERMANENT; 266 conn->flags |= (flags & NCPFL_PERMANENT); 267 } 268 if (mask & NCPFL_PRIMARY) { 269 error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY); 270 if (error) { 271 ncp_conn_unlock(conn, td); 272 break; 273 } 274 } 275 ncp_conn_unlock(conn, td); 276 break; 277 } 278 case NCP_CONN_LOGIN: { 279 struct ncp_conn_login la; 280 281 if (rqsize != sizeof(la)) 282 return EBADRPC; 283 if (conn->flags & NCPFL_LOGGED) 284 return EALREADY; 285 if ((error = copyin(pdata,&la,rqsize)) != 0) 286 break; 287 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE | NCPM_WRITE); 288 if (error) 289 return error; 290 error = ncp_mod_login(conn, la.username, la.objtype, 291 la.password, td, td->td_ucred); 292 ncp_conn_unlock(conn, td); 293 break; 294 } 295 case NCP_CONN_GETINFO: { 296 struct ncp_conn_stat ncs; 297 int len = sizeof(ncs); 298 299 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 300 if (error) 301 return error; 302 ncp_conn_getinfo(conn, &ncs); 303 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 304 error = copyout(&ncs, &args->ioc_ncpbuf->packet, len); 305 ncp_conn_unlock(conn, td); 306 break; 307 } 308 case NCP_CONN_GETUSER: { 309 int len; 310 311 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 312 if (error) 313 return error; 314 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0; 315 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 316 if (len) { 317 error = copyout(conn->li.user, 318 &args->ioc_ncpbuf->packet, len); 319 } 320 ncp_conn_unlock(conn, td); 321 break; 322 } 323 case NCP_CONN_CONN2REF: { 324 int len = sizeof(int); 325 326 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 327 if (error) 328 return error; 329 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 330 if (len) { 331 error = copyout(&conn->nc_id, 332 &args->ioc_ncpbuf->packet, len); 333 } 334 ncp_conn_unlock(conn, td); 335 break; 336 } 337 case NCP_CONN_FRAG: { 338 struct ncp_conn_frag nf; 339 340 if (rqsize != sizeof(nf)) 341 return (EBADRPC); 342 if ((error = copyin(pdata, &nf, rqsize)) != 0) break; 343 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE); 344 if (error) 345 return error; 346 error = ncp_conn_frag_rq(conn, td, &nf); 347 ncp_conn_unlock(conn, td); 348 copyout(&nf, &pdata, sizeof(nf)); 349 td->td_retval[0] = error; 350 break; 351 } 352 case NCP_CONN_DUP: { 353 struct ncp_handle *newhp; 354 int len = sizeof(NWCONN_HANDLE); 355 356 error = ncp_conn_lock(conn, td, cred, NCPM_READ); 357 if (error) break; 358 copyout(&len, &args->ioc_ncpbuf->rpsize, len); 359 error = ncp_conn_gethandle(conn, td, &newhp); 360 if (!error) 361 error = copyout(&newhp->nh_id, 362 args->ioc_ncpbuf->packet, len); 363 ncp_conn_unlock(conn, td); 364 break; 365 } 366 case NCP_CONN_CONNCLOSE: { 367 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE); 368 if (error) break; 369 ncp_conn_puthandle(hp, td, 0); 370 error = ncp_conn_free(conn); 371 if (error) 372 ncp_conn_unlock(conn, td); 373 break; 374 } 375 default: 376 error = EOPNOTSUPP; 377 } 378 return error; 379} 380 381static int 382sncp_conn_scan(struct thread *td, struct ncpioc_connscan *args) 383{ 384 int connHandle = 0, error; 385 struct ncp_conn_args li, *lip; 386 struct ncp_conn *conn; 387 struct ncp_handle *hp; 388 char *user = NULL, *password = NULL; 389 390 if (args->ioc_li) { 391 if (copyin(args->ioc_li, &li, sizeof(li))) 392 return EFAULT; 393 lip = &li; 394 } else { 395 lip = NULL; 396 } 397 398 if (lip != NULL) { 399 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */ 400 ncp_str_upper(lip->server); 401 if (lip->user) { 402 user = ncp_str_dup(lip->user); 403 if (user == NULL) 404 return EINVAL; 405 ncp_str_upper(user); 406 } 407 if (lip->password) { 408 password = ncp_str_dup(lip->password); 409 if (password == NULL) { 410 if (user) 411 free(user, M_NCPDATA); 412 return EINVAL; 413 } 414 ncp_str_upper(password); 415 } 416 lip->user = user; 417 lip->password = password; 418 } 419 error = ncp_conn_getbyli(lip, td, td->td_ucred, NCPM_EXECUTE, &conn); 420 if (!error) { /* already have this login */ 421 ncp_conn_gethandle(conn, td, &hp); 422 connHandle = hp->nh_id; 423 ncp_conn_unlock(conn, td); 424 copyout(&connHandle, args->ioc_connhandle, sizeof(connHandle)); 425 } 426 if (user) 427 free(user, M_NCPDATA); 428 if (password) 429 free(password, M_NCPDATA); 430 return error; 431 432} 433 434int 435ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td, 436 struct ncp_conn_frag *nfp) 437{ 438 NW_FRAGMENT *fp; 439 struct ncp_rq *rqp; 440 u_int32_t fsize; 441 int error, i, rpsize; 442 443 error = ncp_rq_alloc(nfp->fn, conn, td, td->td_ucred, &rqp); 444 if (error) 445 return error; 446 for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) { 447 error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER); 448 if (error) 449 goto bad; 450 } 451 rqp->nr_flags |= NCPR_DONTFREEONERR; 452 error = ncp_request(rqp); 453 if (error) 454 goto bad; 455 rpsize = rqp->nr_rpsize; 456 if (rpsize && nfp->rpfcnt) { 457 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) { 458 error = copyin(&fp->fragSize, &fsize, sizeof (fsize)); 459 if (error) 460 break; 461 fsize = min(fsize, rpsize); 462 error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER); 463 if (error) 464 break; 465 rpsize -= fsize; 466 error = copyout(&fsize, &fp->fragSize, sizeof (fsize)); 467 if (error) 468 break; 469 } 470 } 471 nfp->cs = rqp->nr_cs; 472 nfp->cc = rqp->nr_cc; 473bad: 474 ncp_rq_done(rqp); 475 return error; 476} 477 478static int 479ncp_load(void) 480{ 481 int error; 482 483 if ((error = ncp_init()) != 0) 484 return (error); 485 ncp_dev = make_dev(&ncp_cdevsw, 0, 0, 0, 0666, "ncp"); 486 printf("ncp_load: loaded\n"); 487 return (0); 488} 489 490static int 491ncp_unload(void) 492{ 493 int error; 494 495 error = ncp_done(); 496 if (error) 497 return (error); 498 destroy_dev(ncp_dev); 499 printf("ncp_unload: unloaded\n"); 500 return (0); 501} 502 503static int 504ncp_mod_handler(module_t mod, int type, void *data) 505{ 506 int error; 507 508 switch (type) { 509 case MOD_LOAD: 510 error = ncp_load(); 511 break; 512 case MOD_UNLOAD: 513 error = ncp_unload(); 514 break; 515 default: 516 error = EINVAL; 517 } 518 return error; 519} 520 521static moduledata_t ncp_mod = { 522 "ncp", 523 ncp_mod_handler, 524 NULL 525}; 526DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 527