Pre-2.0 release: Sync with HAMMER 64 - NFS and cross-device link fixes.
[dragonfly.git] / lib / libncp / ncpl_conn.c
blob10afdbdd5ae50cd9eeae38d38ae4aeb0c3b1ec15
1 /*
2 * Copyright (c) 1999, Boris Popov
3 * All rights reserved.
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.
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.
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
43 * and go ahead
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>
52 #include <sys/time.h>
53 #include <sys/mount.h>
54 #include <fcntl.h>
55 #include <ctype.h>
56 #include <errno.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #include <pwd.h>
61 #include <grp.h>
62 #include <unistd.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 ! */
72 int
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);
76 return ENAMETOOLONG;
78 ncp_str_upper(strcpy(li->server, arg));
79 return 0;
82 int
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);
86 return ENAMETOOLONG;
88 if (li->user)
89 free(li->user);
90 if (arg) {
91 li->user = strdup(arg);
92 if (li->user == NULL)
93 return ENOMEM;
94 ncp_str_upper(li->user);
95 } else
96 li->user = NULL;
97 return 0;
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);
104 return ENAMETOOLONG;
106 if (li->password) {
107 bzero(li->password, strlen(li->password));
108 free(li->password);
110 if (passwd) {
111 li->password = strdup(passwd);
112 if (li->password == NULL)
113 return ENOMEM;
114 } else
115 li->password = NULL;
116 return 0;
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[]) {
124 int opt, error = 0;
125 char *arg;
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 */
130 li->access_mode = 0;
131 li->password = NULL;
132 li->sig_level = 1;
133 li->objtype = NCP_BINDERY_USER;
134 li->owner = NCP_DEFAULT_OWNER;
135 li->group = NCP_DEFAULT_GROUP;
136 server_name = NULL;
137 if (argv == NULL) return 0;
138 while (error == 0 && (opt = ncp_getopt(argc, argv, ":S:U:")) != -1) {
139 arg = ncp_optarg;
140 switch (opt) {
141 case 'S':
142 error = ncp_li_setserver(li, arg);
143 break;
144 case 'U':
145 error = ncp_li_setuser(li, arg);
146 break;
149 ncp_optind = ncp_optreset = 1;
150 return error;
153 void
154 ncp_li_done(struct ncp_conn_loginfo *li) {
155 if (li->user)
156 free(li->user);
157 if (li->password)
158 free(li->password);
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;
171 return 0;
173 error = ncp_connect(li, &connHandle);
174 if (error) return errno;
175 error = ncp_login(connHandle, li->user, li->objtype, li->password);
176 if (error) {
177 ncp_disconnect(connHandle);
178 } else
179 *aconnid = connHandle;
180 return error;
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) {
192 int i, val, error;
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) {
201 int connHandle;
202 struct ncp_conn_stat cs;
204 if ((error = ncp_conn_scan(li, &connHandle)) != 0) {
205 ncp_error("no default connection found", errno);
206 return error;
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++) {
217 switch (i) {
218 case 0:
219 sect = li->server;
220 break;
221 case 1:
222 strcat(strcat(strcpy(uname,li->server),":"),li->user ? li->user : "default");
223 sect = uname;
224 break;
226 rc_getstringptr(ncp_rc, sect, "password", &p);
227 if (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;
238 return 0;
242 * check for all uncompleted fields
245 ncp_li_check(struct ncp_conn_loginfo *li) {
246 int error = 0;
247 char *p;
249 do {
250 if (li->server[0] == 0) {
251 ncp_error("no server name specified", 0);
252 error = 1;
253 break;
255 error = ncp_find_fileserver(li,
256 (server_name==NULL) ? AF_IPX : AF_INET, server_name);
257 if (error) {
258 ncp_error("can't find server %s", error, li->server);
259 break;
261 if (li->user == NULL || li->user[0] == 0) {
262 ncp_error("no user name specified for server %s",
263 0, li->server);
264 error = 1;
265 break;
267 if (li->password == NULL) {
268 p = getpass("Netware password:");
269 error = ncp_li_setpassword(li, p) ? 1 : 0;
271 } while (0);
272 return error;
276 ncp_conn_cnt(void) {
277 int error, cnt = 0, len = sizeof(cnt);
279 error = sysctlbyname("net.ncp.conn_cnt", &cnt, &len, NULL, 0);
280 if (error) cnt = 0;
281 return cnt;
285 * Find an existing connection and reference it
288 ncp_conn_find(char *server,char *user) {
289 struct ncp_conn_args ca;
290 int connid, error;
292 if (server == NULL && user == NULL) {
293 error = ncp_conn_scan(NULL,&connid);
294 if (error) return -2;
295 return connid;
297 if (server == NULL)
298 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);
305 if (error)
306 connid = -1;
307 return connid;
311 ncp_li_arg(struct ncp_conn_loginfo *li, int opt, char *arg) {
312 int error = 0, sig_level;
313 char *p, *cp;
314 struct group *gr;
315 struct passwd *pw;
317 switch(opt) {
318 case 'S': /* we already fill server/[user] pair */
319 case 'U':
320 break;
321 case 'A':
322 server_name = arg;
323 break;
324 case 'B':
325 li->opt |= NCP_OPT_BIND;
326 break;
327 case 'C':
328 li->opt |= NCP_OPT_NOUPCASEPASS;
329 break;
330 case 'I':
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);
335 error = 1;
337 li->sig_level = sig_level;
338 if (sig_level > 1) li->opt |= NCP_OPT_SIGN;
339 break;
340 case 'M':
341 li->access_mode = strtol(arg, NULL, 8);
342 break;
343 case 'N':
344 ncp_li_setpassword(li, "");
345 break;
346 case 'O':
347 p = strdup(arg);
348 cp = strchr(p, ':');
349 if (cp) {
350 *cp++ = '\0';
351 if (*cp) {
352 gr = getgrnam(cp);
353 if (gr) {
354 li->group = gr->gr_gid;
355 } else
356 ncp_error("Invalid group name %s, ignored",
357 0, cp);
360 if (*p) {
361 pw = getpwnam(p);
362 if (pw) {
363 li->owner = pw->pw_uid;
364 } else
365 ncp_error("Invalid user name %s, ignored", 0, p);
367 endpwent();
368 free(p);
369 break;
370 case 'P':
371 li->opt |= NCP_OPT_PERMANENT;
372 break;
373 case 'R':
374 li->retry_count = atoi(arg);
375 break;
376 case 'W':
377 li->timeout = atoi(arg);
378 break;
380 return error;
383 void *
384 ncp_conn_list(void) {
385 int error, cnt = 0, len;
386 void *p;
388 cnt = ncp_conn_cnt();
389 if (cnt == 0) return NULL;
390 len = cnt*(sizeof(struct ncp_conn_stat))+sizeof(int);
391 p = malloc(len);
392 if (p == NULL) return NULL;
393 error = sysctlbyname("net.ncp.conn_stat", p, &len, NULL, 0);
394 if (error) {
395 free(p);
396 p = NULL;
398 return p;
403 ncp_conn_setflags(int connid, u_int16_t mask, u_int16_t flags) {
404 int error;
405 DECLARE_RQ;
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)
412 return -1;
413 return error;
417 ncp_login(int connHandle, const char *user, int objtype, const char *password) {
418 int error;
419 struct ncp_conn_login *p;
420 DECLARE_RQ;
422 ncp_init_request(conn);
423 ncp_add_byte(conn, NCP_CONN_LOGIN);
424 p = (struct ncp_conn_login *)&conn->packet[conn->rqsize];
425 p->username = user;
426 p->objtype = objtype;
427 p->password = password;
428 conn->rqsize += sizeof(*p);
429 if ((error = ncp_conn_request(connHandle, conn)) < 0)
430 return -1;
431 return error;
435 ncp_connect_addr(struct sockaddr *sa, NWCONN_HANDLE *chp) {
436 int error;
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);
446 return error;
450 ncp_conn_getinfo(int connHandle, struct ncp_conn_stat *ps) {
451 int error;
452 DECLARE_RQ;
454 ncp_init_request(conn);
455 ncp_add_byte(conn, NCP_CONN_GETINFO);
456 if ((error = ncp_conn_request(connHandle, conn)) < 0)
457 return -1;
458 memcpy(ps, ncp_reply_data(conn,0), sizeof(*ps));
459 return error;
463 ncp_conn_getuser(int connHandle, char **user) {
464 int error;
465 DECLARE_RQ;
467 ncp_init_request(conn);
468 ncp_add_byte(conn, NCP_CONN_GETUSER);
469 if ((error = ncp_conn_request(connHandle, conn)) < 0)
470 return -1;
471 *user = strdup(ncp_reply_data(conn,0));
472 return error;
476 ncp_conn2ref(int connHandle, int *connRef) {
477 int error;
478 DECLARE_RQ;
480 ncp_init_request(conn);
481 ncp_add_byte(conn, NCP_CONN_CONN2REF);
482 if ((error = ncp_conn_request(connHandle, conn)) < 0)
483 return -1;
484 *connRef = *((int*)ncp_reply_data(conn,0));
485 return error;
489 ncp_path2conn(char *path, int *connHandle) {
490 struct statfs st;
491 int d, error;
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;
497 close(d);
498 return 0;
502 ncp_conn_dup(NWCONN_HANDLE org, NWCONN_HANDLE *res) {
503 int error;
504 DECLARE_RQ;
506 ncp_init_request(conn);
507 ncp_add_byte(conn, NCP_CONN_DUP);
508 if ((error = ncp_conn_request(org, conn)) < 0)
509 return errno;
510 *res = *((int*)ncp_reply_data(conn, 0));
511 return 0;