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