2 * Copyright (c) 1999, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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
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.
46 #include <sys/param.h>
47 #include <sys/sysctl.h>
48 #include <sys/ioctl.h>
50 #include <sys/mount.h>
61 #include <netncp/ncp_lib.h>
62 #include <netncp/ncp_rcfile.h>
63 #include <fs/nwfs/nwfs.h>
65 static char *server_name; /* need a better way ! */
70 ncp_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);
75 ncp_str_upper(strcpy(li->server, arg));
80 ncp_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);
88 li->user = strdup(arg);
91 ncp_str_upper(li->user);
98 ncp_li_setpassword(struct ncp_conn_loginfo *li, const char *passwd) {
99 if (passwd && strlen(passwd) >= 127) {
100 ncp_error("password too long", 0);
104 bzero(li->password, strlen(li->password));
108 li->password = strdup(passwd);
109 if (li->password == NULL)
116 * Prescan command line for [-S server] [-U user] arguments
117 * and fill li structure with defaults
120 ncp_li_init(struct ncp_conn_loginfo *li, int argc, char *argv[]) {
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 */
130 li->objtype = NCP_BINDERY_USER;
131 li->owner = NCP_DEFAULT_OWNER;
132 li->group = NCP_DEFAULT_GROUP;
134 if (argv == NULL) return 0;
135 while (error == 0 && (opt = ncp_getopt(argc, argv, ":S:U:")) != -1) {
139 error = ncp_li_setserver(li, arg);
142 error = ncp_li_setuser(li, arg);
146 ncp_optind = ncp_optreset = 1;
151 ncp_li_done(struct ncp_conn_loginfo *li) {
159 * Lookup existing connection based on li structure, if connection
160 * found, it will be referenced. Otherwise full login sequence performed.
163 ncp_li_login(struct ncp_conn_loginfo *li, int *aconnid) {
164 int connHandle, error;
166 if ((error = ncp_conn_scan(li, &connHandle)) == 0) {
167 *aconnid = connHandle;
170 error = ncp_connect(li, &connHandle);
171 if (error) return errno;
172 error = ncp_login(connHandle, li->user, li->objtype, li->password);
174 ncp_disconnect(connHandle);
176 *aconnid = connHandle;
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.
188 ncp_li_readrc(struct ncp_conn_loginfo *li) {
190 char uname[NCP_BINDERY_NAME_LEN*2+1];
191 char *sect = NULL, *p;
194 * if info from cmd line incomplete, try to find existing
195 * connection and fill server/user from it.
197 if (li->server[0] == 0 || li->user == NULL) {
199 struct ncp_conn_stat cs;
201 if ((error = ncp_conn_scan(li, &connHandle)) != 0) {
202 ncp_error("no default connection found", errno);
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);
211 if (ncp_open_rcfile()) return 0;
213 for (i = 0; i < 2; i++) {
219 strcat(strcat(strcpy(uname,li->server),":"),li->user ? li->user : "default");
223 rc_getstringptr(ncp_rc, sect, "password", &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;
239 * check for all uncompleted fields
242 ncp_li_check(struct ncp_conn_loginfo *li) {
247 if (li->server[0] == 0) {
248 ncp_error("no server name specified", 0);
252 error = ncp_find_fileserver(li,
253 (server_name==NULL) ? AF_IPX : AF_INET, server_name);
255 ncp_error("can't find server %s", error, li->server);
258 if (li->user == NULL || li->user[0] == 0) {
259 ncp_error("no user name specified for server %s",
264 if (li->password == NULL) {
265 p = getpass("Netware password:");
266 error = ncp_li_setpassword(li, p) ? 1 : 0;
275 size_t len = sizeof(cnt);
277 error = sysctlbyname("net.ncp.conn_cnt", &cnt, &len, NULL, 0);
283 * Find an existing connection and reference it
286 ncp_conn_find(char *server,char *user) {
287 struct ncp_conn_args ca;
290 if (server == NULL && user == NULL) {
291 error = ncp_conn_scan(NULL,&connid);
292 if (error) 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);
309 ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg) {
310 int error = 0, sig_level;
316 case 'S': /* we already fill server/[user] pair */
323 li->opt |= NCP_OPT_BIND;
326 li->opt |= NCP_OPT_NOUPCASEPASS;
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);
335 li->sig_level = sig_level;
336 if (sig_level > 1) li->opt |= NCP_OPT_SIGN;
339 li->access_mode = strtol(arg, NULL, 8);
342 ncp_li_setpassword(li, "");
352 li->group = gr->gr_gid;
354 ncp_error("invalid group name %s, ignored",
361 li->owner = pw->pw_uid;
363 ncp_error("invalid user name %s, ignored", 0, p);
369 li->opt |= NCP_OPT_PERMANENT;
372 li->retry_count = atoi(arg);
375 li->timeout = atoi(arg);
382 ncp_conn_list(void) {
387 cnt = ncp_conn_cnt();
388 if (cnt == 0) return NULL;
389 len = cnt*(sizeof(struct ncp_conn_stat))+sizeof(int);
391 if (p == NULL) return NULL;
392 error = sysctlbyname("net.ncp.conn_stat", p, &len, NULL, 0);
402 ncp_conn_setflags(int connid, u_int16_t mask, u_int16_t flags) {
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)
416 ncp_login(int connHandle, const char *user, int objtype, const char *password) {
418 struct ncp_conn_login *p;
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)
434 ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp) {
436 struct ncp_conn_args li;
438 bzero(&li, sizeof(li));
439 bcopy(sa, &li.addr, sa->sa_len);
441 * XXX Temporary !!!. server will be filled in kernel !!!
443 strcpy(li.server,ipx_ntoa(li.ipxaddr.sipx_addr));
444 error = ncp_connect(&li, chp);
449 ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps) {
453 ncp_init_request(conn);
454 ncp_add_byte(conn, NCP_CONN_GETINFO);
455 if ((error = ncp_conn_request(connHandle, conn)) < 0)
457 memcpy(ps, ncp_reply_data(conn,0), sizeof(*ps));
462 ncp_conn_getuser(int connHandle, char **user) {
466 ncp_init_request(conn);
467 ncp_add_byte(conn, NCP_CONN_GETUSER);
468 if ((error = ncp_conn_request(connHandle, conn)) < 0)
470 *user = strdup(ncp_reply_data(conn,0));
475 ncp_conn2ref(int connHandle, int *connRef) {
479 ncp_init_request(conn);
480 ncp_add_byte(conn, NCP_CONN_CONN2REF);
481 if ((error = ncp_conn_request(connHandle, conn)) < 0)
483 *connRef = *((int*)ncp_reply_data(conn,0));
488 ncp_path2conn(char *path, int *connHandle) {
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;
501 ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res) {
505 ncp_init_request(conn);
506 ncp_add_byte(conn, NCP_CONN_DUP);
507 if ((error = ncp_conn_request(org, conn)) < 0)
509 *res = *((int*)ncp_reply_data(conn, 0));