ncp_mod.c revision 129880
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 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/netncp/ncp_mod.c 129880 2004-05-30 20:27:19Z phk $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/conf.h> 40#include <sys/proc.h> 41#include <sys/kernel.h> 42#include <sys/module.h> 43#include <sys/sysctl.h> 44#include <sys/malloc.h> 45#include <sys/uio.h> 46#include <sys/ioccom.h> 47 48#include <netncp/ncp.h> 49#include <netncp/ncp_conn.h> 50#include <netncp/ncp_subr.h> 51#include <netncp/ncp_ncp.h> 52#include <netncp/ncp_user.h> 53#include <netncp/ncp_rq.h> 54#include <netncp/ncp_nls.h> 55#include <netncp/ncpio.h> 56 57int ncp_version = NCP_VERSION; 58 59SYSCTL_NODE(_net, OID_AUTO, ncp, CTLFLAG_RW, NULL, "NetWare requester"); 60SYSCTL_INT(_net_ncp, OID_AUTO, version, CTLFLAG_RD, &ncp_version, 0, ""); 61 62MODULE_VERSION(ncp, 1); 63MODULE_DEPEND(ncp, libmchain, 1, 1, 1); 64 65static dev_t ncp_dev; 66 67static d_ioctl_t ncp_ioctl; 68 69static struct cdevsw ncp_cdevsw = { 70 .d_version = D_VERSION, 71 .d_flags = D_NEEDGIANT, 72 .d_ioctl = ncp_ioctl, 73 .d_name = "ncp", 74}; 75 76static int ncp_conn_frag_rq(struct ncp_conn *, struct thread *, 77 struct ncp_conn_frag *); 78static int ncp_conn_handler(struct thread *, struct ncpioc_request *, 79 struct ncp_conn *, struct ncp_handle *); 80static int sncp_conn_scan(struct thread *, struct ncpioc_connscan *); 81static int sncp_connect(struct thread *, struct ncpioc_connect *); 82static int sncp_request(struct thread *, struct ncpioc_request *); 83 84static int 85ncp_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td) 86{ 87 88 switch (cmd) { 89 case NCPIOC_CONNECT: 90 return (sncp_connect(td, (struct ncpioc_connect *)data)); 91 case NCPIOC_CONNSCAN: 92 return (sncp_conn_scan(td, (struct ncpioc_connscan *)data)); 93 case NCPIOC_REQUEST: 94 return (sncp_request(td, (struct ncpioc_request *)data)); 95 } 96 return (EINVAL); 97} 98 99/* 100 * Attach to NCP server 101 */ 102 103static int 104sncp_connect(struct thread *td, struct ncpioc_connect *args) 105{ 106 int connHandle = 0, error; 107 struct ncp_conn *conn; 108 struct ncp_handle *handle; 109 struct ncp_conn_args li; 110 111 checkbad(copyin(args->ioc_li,&li,sizeof(li))); 112 /* XXX Should be useracc() */ 113 checkbad(copyout(&connHandle,args->ioc_connhandle, 114 sizeof(connHandle))); 115 li.password = li.user = NULL; 116 error = ncp_conn_getattached(&li, td, td->td_ucred, NCPM_WRITE | NCPM_EXECUTE, &conn); 117 if (error) { 118 error = ncp_conn_alloc(&li, td, td->td_ucred, &conn); 119 if (error) 120 goto bad; 121 error = ncp_conn_reconnect(conn); 122 if (error) 123 ncp_conn_free(conn); 124 } 125 if (!error) { 126 error = ncp_conn_gethandle(conn, td, &handle); 127 copyout(&handle->nh_id, args->ioc_connhandle, 128 sizeof(args->ioc_connhandle)); 129 ncp_conn_unlock(conn,td); 130 } 131bad: 132 return error; 133} 134 135static int 136sncp_request(struct thread *td, struct ncpioc_request *args) 137{ 138 struct ncp_rq *rqp; 139 struct ncp_conn *conn; 140 struct ncp_handle *handle; 141 int error = 0, rqsize; 142 143 error = ncp_conn_findhandle(args->ioc_connhandle, td, &handle); 144 if (error) 145 return error; 146 conn = handle->nh_conn; 147 if (args->ioc_fn == NCP_CONN) 148 return ncp_conn_handler(td, args, conn, handle); 149 error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int)); 150 if (error) 151 return(error); 152 error = ncp_rq_alloc(args->ioc_fn, conn, td, td->td_ucred, &rqp); 153 if (error) 154 return error; 155 if (rqsize) { 156 error = mb_put_mem(&rqp->rq, (caddr_t)args->ioc_ncpbuf->packet, 157 rqsize, MB_MUSER); 158 if (error) 159 goto bad; 160 } 161 rqp->nr_flags |= NCPR_DONTFREEONERR; 162 error = ncp_request(rqp); 163 if (error == 0 && rqp->nr_rpsize) 164 error = md_get_mem(&rqp->rp, (caddr_t)args->ioc_ncpbuf->packet, 165 rqp->nr_rpsize, MB_MUSER); 166 copyout(&rqp->nr_cs, &args->ioc_ncpbuf->cs, sizeof(rqp->nr_cs)); 167 copyout(&rqp->nr_cc, &args->ioc_ncpbuf->cc, sizeof(rqp->nr_cc)); 168 copyout(&rqp->nr_rpsize, &args->ioc_ncpbuf->rpsize, sizeof(rqp->nr_rpsize)); 169bad: 170 ncp_rq_done(rqp); 171 return error; 172} 173 174static int 175ncp_mod_login(struct ncp_conn *conn, char *user, int objtype, char *password, 176 struct thread *td, struct ucred *cred) 177{ 178 int error; 179 180 if (ncp_suser(cred) != 0 && cred->cr_uid != conn->nc_owner->cr_uid) 181 return EACCES; 182 conn->li.user = ncp_str_dup(user); 183 if (conn->li.user == NULL) 184 return ENOMEM; 185 conn->li.password = ncp_str_dup(password); 186 if (conn->li.password == NULL) { 187 error = ENOMEM; 188 goto bad; 189 } 190 ncp_str_upper(conn->li.user); 191 if ((conn->li.opt & NCP_OPT_NOUPCASEPASS) == 0) 192 ncp_str_upper(conn->li.password); 193 conn->li.objtype = objtype; 194 error = ncp_conn_login(conn, td, cred); 195 return error; 196bad: 197 if (conn->li.user) { 198 free(conn->li.user, M_NCPDATA); 199 conn->li.user = NULL; 200 } 201 if (conn->li.password) { 202 free(conn->li.password, M_NCPDATA); 203 conn->li.password = NULL; 204 } 205 return error; 206} 207 208static int 209ncp_conn_handler(struct thread *td, struct ncpioc_request *args, 210 struct ncp_conn *conn, struct ncp_handle *hp) 211{ 212 int error = 0, rqsize, subfn; 213 struct ucred *cred; 214 215 char *pdata; 216 217 cred = td->td_ucred; 218 error = copyin(&args->ioc_ncpbuf->rqsize, &rqsize, sizeof(int)); 219 if (error) 220 return(error); 221 error = 0; 222 pdata = args->ioc_ncpbuf->packet; 223 subfn = *(pdata++) & 0xff; 224 rqsize--; 225 switch (subfn) { 226 case NCP_CONN_READ: case NCP_CONN_WRITE: { 227 struct ncp_rw rwrq; 228 struct uio auio; 229 struct iovec iov; 230 231 if (rqsize != sizeof(rwrq)) 232 return (EBADRPC); 233 error = copyin(pdata,&rwrq,rqsize); 234 if (error) 235 return (error); 236 iov.iov_base = rwrq.nrw_base; 237 iov.iov_len = rwrq.nrw_cnt; 238 auio.uio_iov = &iov; 239 auio.uio_iovcnt = 1; 240 auio.uio_offset = rwrq.nrw_offset; 241 auio.uio_resid = rwrq.nrw_cnt; 242 auio.uio_segflg = UIO_USERSPACE; 243 auio.uio_rw = (subfn == NCP_CONN_READ) ? UIO_READ : UIO_WRITE; 244 auio.uio_td = td; 245 if (subfn == NCP_CONN_READ) 246 error = ncp_read(conn, &rwrq.nrw_fh, &auio, cred); 247 else 248 error = ncp_write(conn, &rwrq.nrw_fh, &auio, cred); 249 rwrq.nrw_cnt -= auio.uio_resid; 250 /*td->td_retval[0] = rwrq.nrw_cnt;*/ 251 break; 252 } /* case int_read/write */ 253 case NCP_CONN_SETFLAGS: { 254 u_int16_t mask, flags; 255 256 error = copyin(pdata,&mask, sizeof(mask)); 257 if (error) 258 return error; 259 pdata += sizeof(mask); 260 error = copyin(pdata,&flags,sizeof(flags)); 261 if (error) 262 return error; 263 error = ncp_conn_lock(conn, td, cred, NCPM_WRITE); 264 if (error) 265 return error; 266 if (mask & NCPFL_PERMANENT) { 267 conn->flags &= ~NCPFL_PERMANENT; 268 conn->flags |= (flags & NCPFL_PERMANENT); 269 } 270 if (mask & NCPFL_PRIMARY) { 271 error = ncp_conn_setprimary(conn, flags & NCPFL_PRIMARY); 272 if (error) { 273 ncp_conn_unlock(conn, td); 274 break; 275 } 276 } 277 ncp_conn_unlock(conn, td); 278 break; 279 } 280 case NCP_CONN_LOGIN: { 281 struct ncp_conn_login la; 282 283 if (rqsize != sizeof(la)) 284 return EBADRPC; 285 if (conn->flags & NCPFL_LOGGED) 286 return EALREADY; 287 if ((error = copyin(pdata,&la,rqsize)) != 0) 288 break; 289 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE | NCPM_WRITE); 290 if (error) 291 return error; 292 error = ncp_mod_login(conn, la.username, la.objtype, 293 la.password, td, td->td_ucred); 294 ncp_conn_unlock(conn, td); 295 break; 296 } 297 case NCP_CONN_GETINFO: { 298 struct ncp_conn_stat ncs; 299 int len = sizeof(ncs); 300 301 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 302 if (error) 303 return error; 304 ncp_conn_getinfo(conn, &ncs); 305 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 306 error = copyout(&ncs, &args->ioc_ncpbuf->packet, len); 307 ncp_conn_unlock(conn, td); 308 break; 309 } 310 case NCP_CONN_GETUSER: { 311 int len; 312 313 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 314 if (error) 315 return error; 316 len = (conn->li.user) ? strlen(conn->li.user) + 1 : 0; 317 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 318 if (len) { 319 error = copyout(conn->li.user, 320 &args->ioc_ncpbuf->packet, len); 321 } 322 ncp_conn_unlock(conn, td); 323 break; 324 } 325 case NCP_CONN_CONN2REF: { 326 int len = sizeof(int); 327 328 error = ncp_conn_lock(conn, td, td->td_ucred, NCPM_READ); 329 if (error) 330 return error; 331 copyout(&len, &args->ioc_ncpbuf->rpsize, sizeof(int)); 332 if (len) { 333 error = copyout(&conn->nc_id, 334 &args->ioc_ncpbuf->packet, len); 335 } 336 ncp_conn_unlock(conn, td); 337 break; 338 } 339 case NCP_CONN_FRAG: { 340 struct ncp_conn_frag nf; 341 342 if (rqsize != sizeof(nf)) 343 return (EBADRPC); 344 if ((error = copyin(pdata, &nf, rqsize)) != 0) break; 345 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE); 346 if (error) 347 return error; 348 error = ncp_conn_frag_rq(conn, td, &nf); 349 ncp_conn_unlock(conn, td); 350 copyout(&nf, &pdata, sizeof(nf)); 351 td->td_retval[0] = error; 352 break; 353 } 354 case NCP_CONN_DUP: { 355 struct ncp_handle *newhp; 356 int len = sizeof(NWCONN_HANDLE); 357 358 error = ncp_conn_lock(conn, td, cred, NCPM_READ); 359 if (error) break; 360 copyout(&len, &args->ioc_ncpbuf->rpsize, len); 361 error = ncp_conn_gethandle(conn, td, &newhp); 362 if (!error) 363 error = copyout(&newhp->nh_id, 364 args->ioc_ncpbuf->packet, len); 365 ncp_conn_unlock(conn, td); 366 break; 367 } 368 case NCP_CONN_CONNCLOSE: { 369 error = ncp_conn_lock(conn, td, cred, NCPM_EXECUTE); 370 if (error) break; 371 ncp_conn_puthandle(hp, td, 0); 372 error = ncp_conn_free(conn); 373 if (error) 374 ncp_conn_unlock(conn, td); 375 break; 376 } 377 default: 378 error = EOPNOTSUPP; 379 } 380 return error; 381} 382 383static int 384sncp_conn_scan(struct thread *td, struct ncpioc_connscan *args) 385{ 386 int connHandle = 0, error; 387 struct ncp_conn_args li, *lip; 388 struct ncp_conn *conn; 389 struct ncp_handle *hp; 390 char *user = NULL, *password = NULL; 391 392 if (args->ioc_li) { 393 if (copyin(args->ioc_li, &li, sizeof(li))) 394 return EFAULT; 395 lip = &li; 396 } else { 397 lip = NULL; 398 } 399 400 if (lip != NULL) { 401 lip->server[sizeof(lip->server)-1]=0; /* just to make sure */ 402 ncp_str_upper(lip->server); 403 if (lip->user) { 404 user = ncp_str_dup(lip->user); 405 if (user == NULL) 406 return EINVAL; 407 ncp_str_upper(user); 408 } 409 if (lip->password) { 410 password = ncp_str_dup(lip->password); 411 if (password == NULL) { 412 if (user) 413 free(user, M_NCPDATA); 414 return EINVAL; 415 } 416 ncp_str_upper(password); 417 } 418 lip->user = user; 419 lip->password = password; 420 } 421 error = ncp_conn_getbyli(lip, td, td->td_ucred, NCPM_EXECUTE, &conn); 422 if (!error) { /* already have this login */ 423 ncp_conn_gethandle(conn, td, &hp); 424 connHandle = hp->nh_id; 425 ncp_conn_unlock(conn, td); 426 copyout(&connHandle, args->ioc_connhandle, sizeof(connHandle)); 427 } 428 if (user) 429 free(user, M_NCPDATA); 430 if (password) 431 free(password, M_NCPDATA); 432 return error; 433 434} 435 436int 437ncp_conn_frag_rq(struct ncp_conn *conn, struct thread *td, 438 struct ncp_conn_frag *nfp) 439{ 440 NW_FRAGMENT *fp; 441 struct ncp_rq *rqp; 442 u_int32_t fsize; 443 int error, i, rpsize; 444 445 error = ncp_rq_alloc(nfp->fn, conn, td, td->td_ucred, &rqp); 446 if (error) 447 return error; 448 for(fp = nfp->rqf, i = 0; i < nfp->rqfcnt; i++, fp++) { 449 error = mb_put_mem(&rqp->rq, (caddr_t)fp->fragAddress, fp->fragSize, MB_MUSER); 450 if (error) 451 goto bad; 452 } 453 rqp->nr_flags |= NCPR_DONTFREEONERR; 454 error = ncp_request(rqp); 455 if (error) 456 goto bad; 457 rpsize = rqp->nr_rpsize; 458 if (rpsize && nfp->rpfcnt) { 459 for(fp = nfp->rpf, i = 0; i < nfp->rpfcnt; i++, fp++) { 460 error = copyin(&fp->fragSize, &fsize, sizeof (fsize)); 461 if (error) 462 break; 463 fsize = min(fsize, rpsize); 464 error = md_get_mem(&rqp->rp, (caddr_t)fp->fragAddress, fsize, MB_MUSER); 465 if (error) 466 break; 467 rpsize -= fsize; 468 error = copyout(&fsize, &fp->fragSize, sizeof (fsize)); 469 if (error) 470 break; 471 } 472 } 473 nfp->cs = rqp->nr_cs; 474 nfp->cc = rqp->nr_cc; 475bad: 476 ncp_rq_done(rqp); 477 return error; 478} 479 480static int 481ncp_load(void) 482{ 483 int error; 484 485 if ((error = ncp_init()) != 0) 486 return (error); 487 ncp_dev = make_dev(&ncp_cdevsw, 0, 0, 0, 0666, "ncp"); 488 printf("ncp_load: loaded\n"); 489 return (0); 490} 491 492static int 493ncp_unload(void) 494{ 495 int error; 496 497 error = ncp_done(); 498 if (error) 499 return (error); 500 destroy_dev(ncp_dev); 501 printf("ncp_unload: unloaded\n"); 502 return (0); 503} 504 505static int 506ncp_mod_handler(module_t mod, int type, void *data) 507{ 508 int error; 509 510 switch (type) { 511 case MOD_LOAD: 512 error = ncp_load(); 513 break; 514 case MOD_UNLOAD: 515 error = ncp_unload(); 516 break; 517 default: 518 error = EINVAL; 519 } 520 return error; 521} 522 523static moduledata_t ncp_mod = { 524 "ncp", 525 ncp_mod_handler, 526 NULL 527}; 528DECLARE_MODULE(ncp, ncp_mod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); 529