ncpl_conn.c revision 165920
1/* 2 * Copyright (c) 1999, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/lib/libncp/ncpl_conn.c 165920 2007-01-09 23:27:39Z imp $"); 32 33/* 34 * 35 * Current scheme to create/open connection: 36 * 1. ncp_li_init() - lookup -S [-U] options in command line 37 * 2. ncp_li_init() - try to find existing connection 38 * 3. ncp_li_init() - if no server name and no accessible connections - bail out 39 * 4. This is connection candidate, read .rc file, override with command line 40 * and go ahead 41 * Note: connection referenced only via ncp_login() call. Although it is 42 * possible to get connection handle in other way, it will be unwise to use 43 * it, since conn can be destroyed at any time. 44 * 45 */ 46#include <sys/param.h> 47#include <sys/sysctl.h> 48#include <sys/ioctl.h> 49#include <sys/time.h> 50#include <sys/mount.h> 51#include <fcntl.h> 52#include <ctype.h> 53#include <errno.h> 54#include <stdio.h> 55#include <string.h> 56#include <stdlib.h> 57#include <pwd.h> 58#include <grp.h> 59#include <unistd.h> 60 61#include <netncp/ncp_lib.h> 62#include <netncp/ncp_rcfile.h> 63#include <fs/nwfs/nwfs.h> 64 65static char *server_name; /* need a better way ! */ 66 67 68 69int 70ncp_li_setserver(struct ncp_conn_loginfo *li, const char *arg) { 71 if (strlen(arg) >= NCP_BINDERY_NAME_LEN) { 72 ncp_error("server name '%s' too long", 0, arg); 73 return ENAMETOOLONG; 74 } 75 ncp_str_upper(strcpy(li->server, arg)); 76 return 0; 77} 78 79int 80ncp_li_setuser(struct ncp_conn_loginfo *li, char *arg) { 81 if (arg && strlen(arg) >= NCP_BINDERY_NAME_LEN) { 82 ncp_error("user name '%s' too long", 0, arg); 83 return ENAMETOOLONG; 84 } 85 if (li->user) 86 free(li->user); 87 if (arg) { 88 li->user = strdup(arg); 89 if (li->user == NULL) 90 return ENOMEM; 91 ncp_str_upper(li->user); 92 } else 93 li->user = NULL; 94 return 0; 95} 96 97int 98ncp_li_setpassword(struct ncp_conn_loginfo *li, const char *passwd) { 99 if (passwd && strlen(passwd) >= 127) { 100 ncp_error("password too long", 0); 101 return ENAMETOOLONG; 102 } 103 if (li->password) { 104 bzero(li->password, strlen(li->password)); 105 free(li->password); 106 } 107 if (passwd) { 108 li->password = strdup(passwd); 109 if (li->password == NULL) 110 return ENOMEM; 111 } else 112 li->password = NULL; 113 return 0; 114} 115/* 116 * Prescan command line for [-S server] [-U user] arguments 117 * and fill li structure with defaults 118 */ 119int 120ncp_li_init(struct ncp_conn_loginfo *li, int argc, char *argv[]) { 121 int opt, error = 0; 122 char *arg; 123 124 bzero(li,sizeof(*li)); 125 li->timeout = 15; /* these values should be large enough to handle */ 126 li->retry_count = 4; /* slow servers, even on ethernet */ 127 li->access_mode = 0; 128 li->password = NULL; 129 li->sig_level = 1; 130 li->objtype = NCP_BINDERY_USER; 131 li->owner = NCP_DEFAULT_OWNER; 132 li->group = NCP_DEFAULT_GROUP; 133 server_name = NULL; 134 if (argv == NULL) return 0; 135 while (error == 0 && (opt = ncp_getopt(argc, argv, ":S:U:")) != -1) { 136 arg = ncp_optarg; 137 switch (opt) { 138 case 'S': 139 error = ncp_li_setserver(li, arg); 140 break; 141 case 'U': 142 error = ncp_li_setuser(li, arg); 143 break; 144 } 145 } 146 ncp_optind = ncp_optreset = 1; 147 return error; 148} 149 150void 151ncp_li_done(struct ncp_conn_loginfo *li) { 152 if (li->user) 153 free(li->user); 154 if (li->password) 155 free(li->password); 156} 157 158/* 159 * Lookup existing connection based on li structure, if connection 160 * found, it will be referenced. Otherwise full login sequence performed. 161 */ 162int 163ncp_li_login(struct ncp_conn_loginfo *li, int *aconnid) { 164 int connHandle, error; 165 166 if ((error = ncp_conn_scan(li, &connHandle)) == 0) { 167 *aconnid = connHandle; 168 return 0; 169 } 170 error = ncp_connect(li, &connHandle); 171 if (error) return errno; 172 error = ncp_login(connHandle, li->user, li->objtype, li->password); 173 if (error) { 174 ncp_disconnect(connHandle); 175 } else 176 *aconnid = connHandle; 177 return error; 178} 179 180/* 181 * read rc file as follows: 182 * 1. read [server] section 183 * 2. override with [server:user] section 184 * Since abcence of rcfile is not a bug, silently ignore that fact. 185 * rcfile never closed to reduce number of open/close operations. 186 */ 187int 188ncp_li_readrc(struct ncp_conn_loginfo *li) { 189 int i, val, error; 190 char uname[NCP_BINDERY_NAME_LEN*2+1]; 191 char *sect = NULL, *p; 192 193 /* 194 * if info from cmd line incomplete, try to find existing 195 * connection and fill server/user from it. 196 */ 197 if (li->server[0] == 0 || li->user == NULL) { 198 int connHandle; 199 struct ncp_conn_stat cs; 200 201 if ((error = ncp_conn_scan(li, &connHandle)) != 0) { 202 ncp_error("no default connection found", errno); 203 return error; 204 } 205 ncp_conn_getinfo(connHandle, &cs); 206 ncp_li_setserver(li, cs.li.server); 207 ncp_li_setuser(li, cs.user); 208 ncp_li_setpassword(li, ""); 209 ncp_disconnect(connHandle); 210 } 211 if (ncp_open_rcfile()) return 0; 212 213 for (i = 0; i < 2; i++) { 214 switch (i) { 215 case 0: 216 sect = li->server; 217 break; 218 case 1: 219 strcat(strcat(strcpy(uname,li->server),":"),li->user ? li->user : "default"); 220 sect = uname; 221 break; 222 } 223 rc_getstringptr(ncp_rc, sect, "password", &p); 224 if (p) 225 ncp_li_setpassword(li, p); 226 rc_getint(ncp_rc,sect, "timeout", &li->timeout); 227 rc_getint(ncp_rc,sect, "retry_count", &li->retry_count); 228 rc_getint(ncp_rc,sect, "sig_level", &li->sig_level); 229 if (rc_getint(ncp_rc,sect,"access_mode",&val) == 0) 230 li->access_mode = val; 231 if(rc_getbool(ncp_rc,sect,"bindery",&val) == 0 && val) { 232 li->opt |= NCP_OPT_BIND; 233 } 234 } 235 return 0; 236} 237 238/* 239 * check for all uncompleted fields 240 */ 241int 242ncp_li_check(struct ncp_conn_loginfo *li) { 243 int error = 0; 244 char *p; 245 246 do { 247 if (li->server[0] == 0) { 248 ncp_error("no server name specified", 0); 249 error = 1; 250 break; 251 } 252 error = ncp_find_fileserver(li, 253 (server_name==NULL) ? AF_IPX : AF_INET, server_name); 254 if (error) { 255 ncp_error("can't find server %s", error, li->server); 256 break; 257 } 258 if (li->user == NULL || li->user[0] == 0) { 259 ncp_error("no user name specified for server %s", 260 0, li->server); 261 error = 1; 262 break; 263 } 264 if (li->password == NULL) { 265 p = getpass("Netware password:"); 266 error = ncp_li_setpassword(li, p) ? 1 : 0; 267 } 268 } while (0); 269 return error; 270} 271 272int 273ncp_conn_cnt(void) { 274 int error, cnt = 0; 275 size_t len = sizeof(cnt); 276 277 error = sysctlbyname("net.ncp.conn_cnt", &cnt, &len, NULL, 0); 278 if (error) cnt = 0; 279 return cnt; 280} 281 282/* 283 * Find an existing connection and reference it 284 */ 285int 286ncp_conn_find(char *server,char *user) { 287 struct ncp_conn_args ca; 288 int connid, error; 289 290 if (server == NULL && user == NULL) { 291 error = ncp_conn_scan(NULL,&connid); 292 if (error) return -2; 293 return connid; 294 } 295 if (server == NULL) 296 return -2; 297 ncp_str_upper(server); 298 if (user) ncp_str_upper(user); 299 bzero(&ca, sizeof(ca)); 300 ncp_li_setserver(&ca, server); 301 ncp_li_setuser(&ca, user); 302 error = ncp_conn_scan(&ca,&connid); 303 if (error) 304 connid = -1; 305 return connid; 306} 307 308int 309ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg) { 310 int error = 0, sig_level; 311 char *p, *cp; 312 struct group *gr; 313 struct passwd *pw; 314 315 switch(opt) { 316 case 'S': /* we already fill server/[user] pair */ 317 case 'U': 318 break; 319 case 'A': 320 server_name = arg; 321 break; 322 case 'B': 323 li->opt |= NCP_OPT_BIND; 324 break; 325 case 'C': 326 li->opt |= NCP_OPT_NOUPCASEPASS; 327 break; 328 case 'I': 329 sig_level = atoi(arg); 330 if (sig_level < 0 || sig_level > 3) { 331 ncp_error("invalid NCP signature level option `%s'\ 332 (must be a number between 0 and 3)", 0, arg); 333 error = 1; 334 } 335 li->sig_level = sig_level; 336 if (sig_level > 1) li->opt |= NCP_OPT_SIGN; 337 break; 338 case 'M': 339 li->access_mode = strtol(arg, NULL, 8); 340 break; 341 case 'N': 342 ncp_li_setpassword(li, ""); 343 break; 344 case 'O': 345 p = strdup(arg); 346 cp = strchr(p, ':'); 347 if (cp) { 348 *cp++ = '\0'; 349 if (*cp) { 350 gr = getgrnam(cp); 351 if (gr) { 352 li->group = gr->gr_gid; 353 } else 354 ncp_error("invalid group name %s, ignored", 355 0, cp); 356 } 357 } 358 if (*p) { 359 pw = getpwnam(p); 360 if (pw) { 361 li->owner = pw->pw_uid; 362 } else 363 ncp_error("invalid user name %s, ignored", 0, p); 364 } 365 endpwent(); 366 free(p); 367 break; 368 case 'P': 369 li->opt |= NCP_OPT_PERMANENT; 370 break; 371 case 'R': 372 li->retry_count = atoi(arg); 373 break; 374 case 'W': 375 li->timeout = atoi(arg); 376 break; 377 } 378 return error; 379} 380 381void * 382ncp_conn_list(void) { 383 int error, cnt = 0; 384 size_t len; 385 void *p; 386 387 cnt = ncp_conn_cnt(); 388 if (cnt == 0) return NULL; 389 len = cnt*(sizeof(struct ncp_conn_stat))+sizeof(int); 390 p = malloc(len); 391 if (p == NULL) return NULL; 392 error = sysctlbyname("net.ncp.conn_stat", p, &len, NULL, 0); 393 if (error) { 394 free(p); 395 p = NULL; 396 } 397 return p; 398} 399 400 401int 402ncp_conn_setflags(int connid, u_int16_t mask, u_int16_t flags) { 403 int error; 404 DECLARE_RQ; 405 406 ncp_init_request(conn); 407 ncp_add_byte(conn, NCP_CONN_SETFLAGS); 408 ncp_add_word_lh(conn, mask); 409 ncp_add_word_lh(conn, flags); 410 if ((error = ncp_conn_request(connid, conn)) < 0) 411 return -1; 412 return error; 413} 414 415int 416ncp_login(int connHandle, const char *user, int objtype, const char *password) { 417 int error; 418 struct ncp_conn_login *p; 419 DECLARE_RQ; 420 421 ncp_init_request(conn); 422 ncp_add_byte(conn, NCP_CONN_LOGIN); 423 p = (struct ncp_conn_login *)&conn->packet[conn->rqsize]; 424 p->username = (char *)user; 425 p->objtype = objtype; 426 p->password = (char *)password; 427 conn->rqsize += sizeof(*p); 428 if ((error = ncp_conn_request(connHandle, conn)) < 0) 429 return -1; 430 return error; 431} 432 433int 434ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp) { 435 int error; 436 struct ncp_conn_args li; 437 438 bzero(&li, sizeof(li)); 439 bcopy(sa, &li.addr, sa->sa_len); 440 /* 441 * XXX Temporary !!!. server will be filled in kernel !!! 442 */ 443 strcpy(li.server,ipx_ntoa(li.ipxaddr.sipx_addr)); 444 error = ncp_connect(&li, chp); 445 return error; 446} 447 448int 449ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps) { 450 int error; 451 DECLARE_RQ; 452 453 ncp_init_request(conn); 454 ncp_add_byte(conn, NCP_CONN_GETINFO); 455 if ((error = ncp_conn_request(connHandle, conn)) < 0) 456 return -1; 457 memcpy(ps, ncp_reply_data(conn,0), sizeof(*ps)); 458 return error; 459} 460 461int 462ncp_conn_getuser(int connHandle, char **user) { 463 int error; 464 DECLARE_RQ; 465 466 ncp_init_request(conn); 467 ncp_add_byte(conn, NCP_CONN_GETUSER); 468 if ((error = ncp_conn_request(connHandle, conn)) < 0) 469 return -1; 470 *user = strdup(ncp_reply_data(conn,0)); 471 return error; 472} 473 474int 475ncp_conn2ref(int connHandle, int *connRef) { 476 int error; 477 DECLARE_RQ; 478 479 ncp_init_request(conn); 480 ncp_add_byte(conn, NCP_CONN_CONN2REF); 481 if ((error = ncp_conn_request(connHandle, conn)) < 0) 482 return -1; 483 *connRef = *((int*)ncp_reply_data(conn,0)); 484 return error; 485} 486 487int 488ncp_path2conn(char *path, int *connHandle) { 489 struct statfs st; 490 int d, error; 491 492 if ((error = statfs(path, &st)) != 0) return errno; 493 if (strcmp(st.f_fstypename,"nwfs") != 0) return EINVAL; 494 if ((d = open(path, O_RDONLY)) < 0) return errno; 495 if ((error = ioctl(d,NWFSIOC_GETCONN, connHandle)) != 0) return errno; 496 close(d); 497 return 0; 498} 499 500int 501ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res) { 502 int error; 503 DECLARE_RQ; 504 505 ncp_init_request(conn); 506 ncp_add_byte(conn, NCP_CONN_DUP); 507 if ((error = ncp_conn_request(org, conn)) < 0) 508 return errno; 509 *res = *((int*)ncp_reply_data(conn, 0)); 510 return 0; 511} 512