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. 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.
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
32 * $FreeBSD: src/lib/libncp/ncpl_conn.c,v 1.2 1999/10/29 12:59:59 bp Exp $
33 * $DragonFly: src/lib/libncp/ncpl_conn.c,v 1.4 2005/02/28 16:23:25 joerg Exp $
38 * Current scheme to create/open connection:
39 * 1. ncp_li_init() - lookup -S [-U] options in command line
40 * 2. ncp_li_init() - try to find existing connection
41 * 3. ncp_li_init() - if no server name and no accessible connections - bail out
42 * 4. This is connection candidate, read .rc file, override with command line
44 * Note: connection referenced only via ncp_login() call. Although it is
45 * possible to get connection handle in other way, it will be unwise to use
46 * it, since conn can be destroyed at any time.
49 #include <sys/param.h>
50 #include <sys/sysctl.h>
51 #include <sys/ioctl.h>
53 #include <sys/mount.h>
64 #include <netncp/ncp_lib.h>
65 #include <netncp/ncp_rcfile.h>
66 #include <nwfs/nwfs.h>
68 static char *server_name
; /* need a better way ! */
73 ncp_li_setserver(struct ncp_conn_loginfo
*li
, const char *arg
) {
74 if (strlen(arg
) >= NCP_BINDERY_NAME_LEN
) {
75 ncp_error("server name '%s' too long", 0, arg
);
78 ncp_str_upper(strcpy(li
->server
, arg
));
83 ncp_li_setuser(struct ncp_conn_loginfo
*li
, char *arg
) {
84 if (arg
&& strlen(arg
) >= NCP_BINDERY_NAME_LEN
) {
85 ncp_error("user name '%s' too long", 0, arg
);
91 li
->user
= strdup(arg
);
94 ncp_str_upper(li
->user
);
101 ncp_li_setpassword(struct ncp_conn_loginfo
*li
, const char *passwd
) {
102 if (passwd
&& strlen(passwd
) >= 127) {
103 ncp_error("password too long", 0);
107 bzero(li
->password
, strlen(li
->password
));
111 li
->password
= strdup(passwd
);
112 if (li
->password
== NULL
)
119 * Prescan command line for [-S server] [-U user] arguments
120 * and fill li structure with defaults
123 ncp_li_init(struct ncp_conn_loginfo
*li
, int argc
, char *argv
[]) {
127 bzero(li
,sizeof(*li
));
128 li
->timeout
= 15; /* these values should be large enough to handle */
129 li
->retry_count
= 4; /* slow servers, even on ethernet */
133 li
->objtype
= NCP_BINDERY_USER
;
134 li
->owner
= NCP_DEFAULT_OWNER
;
135 li
->group
= NCP_DEFAULT_GROUP
;
137 if (argv
== NULL
) return 0;
138 while (error
== 0 && (opt
= ncp_getopt(argc
, argv
, ":S:U:")) != -1) {
142 error
= ncp_li_setserver(li
, arg
);
145 error
= ncp_li_setuser(li
, arg
);
149 ncp_optind
= ncp_optreset
= 1;
154 ncp_li_done(struct ncp_conn_loginfo
*li
) {
162 * Lookup existing connection based on li structure, if connection
163 * found, it will be referenced. Otherwise full login sequence performed.
166 ncp_li_login(struct ncp_conn_loginfo
*li
, int *aconnid
) {
167 int connHandle
, error
;
169 if ((error
= ncp_conn_scan(li
, &connHandle
)) == 0) {
170 *aconnid
= connHandle
;
173 error
= ncp_connect(li
, &connHandle
);
174 if (error
) return errno
;
175 error
= ncp_login(connHandle
, li
->user
, li
->objtype
, li
->password
);
177 ncp_disconnect(connHandle
);
179 *aconnid
= connHandle
;
184 * read rc file as follows:
185 * 1. read [server] section
186 * 2. override with [server:user] section
187 * Since abcence of rcfile is not a bug, silently ignore that fact.
188 * rcfile never closed to reduce number of open/close operations.
191 ncp_li_readrc(struct ncp_conn_loginfo
*li
) {
193 char uname
[NCP_BINDERY_NAME_LEN
*2+1];
194 char *sect
= NULL
, *p
;
197 * if info from cmd line incomplete, try to find existing
198 * connection and fill server/user from it.
200 if (li
->server
[0] == 0 || li
->user
== NULL
) {
202 struct ncp_conn_stat cs
;
204 if ((error
= ncp_conn_scan(li
, &connHandle
)) != 0) {
205 ncp_error("no default connection found", errno
);
208 ncp_conn_getinfo(connHandle
, &cs
);
209 ncp_li_setserver(li
, cs
.li
.server
);
210 ncp_li_setuser(li
, cs
.user
);
211 ncp_li_setpassword(li
, "");
212 ncp_disconnect(connHandle
);
214 if (ncp_open_rcfile()) return 0;
216 for (i
= 0; i
< 2; i
++) {
222 strcat(strcat(strcpy(uname
,li
->server
),":"),li
->user
? li
->user
: "default");
226 rc_getstringptr(ncp_rc
, sect
, "password", &p
);
228 ncp_li_setpassword(li
, p
);
229 rc_getint(ncp_rc
,sect
, "timeout", &li
->timeout
);
230 rc_getint(ncp_rc
,sect
, "retry_count", &li
->retry_count
);
231 rc_getint(ncp_rc
,sect
, "sig_level", &li
->sig_level
);
232 if (rc_getint(ncp_rc
,sect
,"access_mode",&val
) == 0)
233 li
->access_mode
= val
;
234 if(rc_getbool(ncp_rc
,sect
,"bindery",&val
) == 0 && val
) {
235 li
->opt
|= NCP_OPT_BIND
;
242 * check for all uncompleted fields
245 ncp_li_check(struct ncp_conn_loginfo
*li
) {
250 if (li
->server
[0] == 0) {
251 ncp_error("no server name specified", 0);
255 error
= ncp_find_fileserver(li
,
256 (server_name
==NULL
) ? AF_IPX
: AF_INET
, server_name
);
258 ncp_error("can't find server %s", error
, li
->server
);
261 if (li
->user
== NULL
|| li
->user
[0] == 0) {
262 ncp_error("no user name specified for server %s",
267 if (li
->password
== NULL
) {
268 p
= getpass("Netware password:");
269 error
= ncp_li_setpassword(li
, p
) ? 1 : 0;
277 int error
, cnt
= 0, len
= sizeof(cnt
);
279 error
= sysctlbyname("net.ncp.conn_cnt", &cnt
, &len
, NULL
, 0);
285 * Find an existing connection and reference it
288 ncp_conn_find(char *server
,char *user
) {
289 struct ncp_conn_args ca
;
292 if (server
== NULL
&& user
== NULL
) {
293 error
= ncp_conn_scan(NULL
,&connid
);
294 if (error
) return -2;
299 ncp_str_upper(server
);
300 if (user
) ncp_str_upper(user
);
301 bzero(&ca
, sizeof(ca
));
302 ncp_li_setserver(&ca
, server
);
303 ncp_li_setuser(&ca
, user
);
304 error
= ncp_conn_scan(&ca
,&connid
);
311 ncp_li_arg(struct ncp_conn_loginfo
*li
, int opt
, char *arg
) {
312 int error
= 0, sig_level
;
318 case 'S': /* we already fill server/[user] pair */
325 li
->opt
|= NCP_OPT_BIND
;
328 li
->opt
|= NCP_OPT_NOUPCASEPASS
;
331 sig_level
= atoi(arg
);
332 if (sig_level
< 0 || sig_level
> 3) {
333 ncp_error("invalid NCP signature level option `%s'\
334 (must be a number between 0 and 3)", 0, arg
);
337 li
->sig_level
= sig_level
;
338 if (sig_level
> 1) li
->opt
|= NCP_OPT_SIGN
;
341 li
->access_mode
= strtol(arg
, NULL
, 8);
344 ncp_li_setpassword(li
, "");
354 li
->group
= gr
->gr_gid
;
356 ncp_error("Invalid group name %s, ignored",
363 li
->owner
= pw
->pw_uid
;
365 ncp_error("Invalid user name %s, ignored", 0, p
);
371 li
->opt
|= NCP_OPT_PERMANENT
;
374 li
->retry_count
= atoi(arg
);
377 li
->timeout
= atoi(arg
);
384 ncp_conn_list(void) {
385 int error
, cnt
= 0, len
;
388 cnt
= ncp_conn_cnt();
389 if (cnt
== 0) return NULL
;
390 len
= cnt
*(sizeof(struct ncp_conn_stat
))+sizeof(int);
392 if (p
== NULL
) return NULL
;
393 error
= sysctlbyname("net.ncp.conn_stat", p
, &len
, NULL
, 0);
403 ncp_conn_setflags(int connid
, u_int16_t mask
, u_int16_t flags
) {
407 ncp_init_request(conn
);
408 ncp_add_byte(conn
, NCP_CONN_SETFLAGS
);
409 ncp_add_word_lh(conn
, mask
);
410 ncp_add_word_lh(conn
, flags
);
411 if ((error
= ncp_conn_request(connid
, conn
)) < 0)
417 ncp_login(int connHandle
, const char *user
, int objtype
, const char *password
) {
419 struct ncp_conn_login
*p
;
422 ncp_init_request(conn
);
423 ncp_add_byte(conn
, NCP_CONN_LOGIN
);
424 p
= (struct ncp_conn_login
*)&conn
->packet
[conn
->rqsize
];
426 p
->objtype
= objtype
;
427 p
->password
= password
;
428 conn
->rqsize
+= sizeof(*p
);
429 if ((error
= ncp_conn_request(connHandle
, conn
)) < 0)
435 ncp_connect_addr(struct sockaddr
*sa
, NWCONN_HANDLE
*chp
) {
437 struct ncp_conn_args li
;
439 bzero(&li
, sizeof(li
));
440 bcopy(sa
, &li
.addr
, sa
->sa_len
);
442 * XXX Temporary !!!. server will be filled in kernel !!!
444 strcpy(li
.server
,ipx_ntoa(li
.ipxaddr
.sipx_addr
));
445 error
= ncp_connect(&li
, chp
);
450 ncp_conn_getinfo(int connHandle
, struct ncp_conn_stat
*ps
) {
454 ncp_init_request(conn
);
455 ncp_add_byte(conn
, NCP_CONN_GETINFO
);
456 if ((error
= ncp_conn_request(connHandle
, conn
)) < 0)
458 memcpy(ps
, ncp_reply_data(conn
,0), sizeof(*ps
));
463 ncp_conn_getuser(int connHandle
, char **user
) {
467 ncp_init_request(conn
);
468 ncp_add_byte(conn
, NCP_CONN_GETUSER
);
469 if ((error
= ncp_conn_request(connHandle
, conn
)) < 0)
471 *user
= strdup(ncp_reply_data(conn
,0));
476 ncp_conn2ref(int connHandle
, int *connRef
) {
480 ncp_init_request(conn
);
481 ncp_add_byte(conn
, NCP_CONN_CONN2REF
);
482 if ((error
= ncp_conn_request(connHandle
, conn
)) < 0)
484 *connRef
= *((int*)ncp_reply_data(conn
,0));
489 ncp_path2conn(char *path
, int *connHandle
) {
493 if ((error
= statfs(path
, &st
)) != 0) return errno
;
494 if (strcmp(st
.f_fstypename
,"nwfs") != 0) return EINVAL
;
495 if ((d
= open(path
, O_RDONLY
)) < 0) return errno
;
496 if ((error
= ioctl(d
,NWFSIOC_GETCONN
, connHandle
)) != 0) return errno
;
502 ncp_conn_dup(NWCONN_HANDLE org
, NWCONN_HANDLE
*res
) {
506 ncp_init_request(conn
);
507 ncp_add_byte(conn
, NCP_CONN_DUP
);
508 if ((error
= ncp_conn_request(org
, conn
)) < 0)
510 *res
= *((int*)ncp_reply_data(conn
, 0));