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: stable/9/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
65 static char *server_name; /* need a better way ! */
66
67
68
69 int
ncp_li_setserver(struct ncp_conn_loginfo * li,const char * arg)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);
73 return ENAMETOOLONG;
74 }
75 ncp_str_upper(strcpy(li->server, arg));
76 return 0;
77 }
78
79 int
ncp_li_setuser(struct ncp_conn_loginfo * li,char * 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);
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
97 int
ncp_li_setpassword(struct ncp_conn_loginfo * li,const char * passwd)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);
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 */
119 int
ncp_li_init(struct ncp_conn_loginfo * li,int argc,char * argv[])120 ncp_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
150 void
ncp_li_done(struct ncp_conn_loginfo * li)151 ncp_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 */
162 int
ncp_li_login(struct ncp_conn_loginfo * li,int * aconnid)163 ncp_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 */
187 int
ncp_li_readrc(struct ncp_conn_loginfo * li)188 ncp_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 */
241 int
ncp_li_check(struct ncp_conn_loginfo * li)242 ncp_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
272 int
ncp_conn_cnt(void)273 ncp_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 */
285 int
ncp_conn_find(char * server,char * user)286 ncp_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
308 int
ncp_li_arg(struct ncp_conn_loginfo * li,int opt,char * arg)309 ncp_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
381 void *
ncp_conn_list(void)382 ncp_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
401 int
ncp_conn_setflags(int connid,u_int16_t mask,u_int16_t flags)402 ncp_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
415 int
ncp_login(int connHandle,const char * user,int objtype,const char * password)416 ncp_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
433 int
ncp_connect_addr(struct sockaddr * sa,NWCONN_HANDLE * chp)434 ncp_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
448 int
ncp_conn_getinfo(int connHandle,struct ncp_conn_stat * ps)449 ncp_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
461 int
ncp_conn_getuser(int connHandle,char ** user)462 ncp_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
474 int
ncp_conn2ref(int connHandle,int * connRef)475 ncp_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
487 int
ncp_path2conn(char * path,int * connHandle)488 ncp_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
500 int
ncp_conn_dup(NWCONN_HANDLE org,NWCONN_HANDLE * res)501 ncp_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