00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "includes.h"
00026
00027 #include "include/libsmb_internal.h"
00028
00029 struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir);
00030 struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list,
00031 struct smbc_dirent *dirent);
00032
00033
00034
00035
00036 typedef struct DOS_ATTR_DESC {
00037 int mode;
00038 SMB_OFF_T size;
00039 time_t create_time;
00040 time_t access_time;
00041 time_t write_time;
00042 time_t change_time;
00043 SMB_INO_T inode;
00044 } DOS_ATTR_DESC;
00045
00046
00047
00048
00049
00050
00051
00052 #define SMBC_XATTR_MODE_ADD 1
00053 #define SMBC_XATTR_MODE_REMOVE 2
00054 #define SMBC_XATTR_MODE_REMOVE_ALL 3
00055 #define SMBC_XATTR_MODE_SET 4
00056 #define SMBC_XATTR_MODE_CHOWN 5
00057 #define SMBC_XATTR_MODE_CHGRP 6
00058
00059 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
00060
00061
00062 #ifndef ENOTSUP
00063 #define ENOTSUP EOPNOTSUPP
00064 #endif
00065
00066
00067
00068
00069 int smbc_default_cache_functions(SMBCCTX *context);
00070
00071
00072
00073
00074
00075
00076
00077 static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
00078 if (!p || !list) return False;
00079 do {
00080 if (p == list) return True;
00081 list = list->next;
00082 } while (list);
00083 return False;
00084 }
00085
00086
00087
00088
00089 static struct rpc_pipe_client *
00090 find_lsa_pipe_hnd(struct cli_state *ipc_cli)
00091 {
00092 struct rpc_pipe_client *pipe_hnd;
00093
00094 for (pipe_hnd = ipc_cli->pipe_list;
00095 pipe_hnd;
00096 pipe_hnd = pipe_hnd->next) {
00097
00098 if (pipe_hnd->pipe_idx == PI_LSARPC) {
00099 return pipe_hnd;
00100 }
00101 }
00102
00103 return NULL;
00104 }
00105
00106 static int
00107 smbc_close_ctx(SMBCCTX *context,
00108 SMBCFILE *file);
00109 static off_t
00110 smbc_lseek_ctx(SMBCCTX *context,
00111 SMBCFILE *file,
00112 off_t offset,
00113 int whence);
00114
00115 extern BOOL in_client;
00116
00117
00118
00119
00120 static int smbc_initialized = 0;
00121
00122 static int
00123 hex2int( unsigned int _char )
00124 {
00125 if ( _char >= 'A' && _char <='F')
00126 return _char - 'A' + 10;
00127 if ( _char >= 'a' && _char <='f')
00128 return _char - 'a' + 10;
00129 if ( _char >= '0' && _char <='9')
00130 return _char - '0';
00131 return -1;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 int
00146 smbc_urldecode(char *dest, char * src, size_t max_dest_len)
00147 {
00148 int old_length = strlen(src);
00149 int i = 0;
00150 int err_count = 0;
00151 pstring temp;
00152 char * p;
00153
00154 if ( old_length == 0 ) {
00155 return 0;
00156 }
00157
00158 p = temp;
00159 while ( i < old_length ) {
00160 unsigned char character = src[ i++ ];
00161
00162 if (character == '%') {
00163 int a = i+1 < old_length ? hex2int( src[i] ) : -1;
00164 int b = i+1 < old_length ? hex2int( src[i+1] ) : -1;
00165
00166
00167 if (a != -1 && b != -1) {
00168
00169
00170 character = (a * 16) + b;
00171
00172 if (character == '\0') {
00173 break;
00174 }
00175
00176 i += 2;
00177 } else {
00178
00179 err_count++;
00180 }
00181 }
00182
00183 *p++ = character;
00184 }
00185
00186 *p = '\0';
00187
00188 strncpy(dest, temp, max_dest_len - 1);
00189 dest[max_dest_len - 1] = '\0';
00190
00191 return err_count;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 int
00203 smbc_urlencode(char * dest, char * src, int max_dest_len)
00204 {
00205 char hex[] = "0123456789ABCDEF";
00206
00207 for (; *src != '\0' && max_dest_len >= 3; src++) {
00208
00209 if ((*src < '0' &&
00210 *src != '-' &&
00211 *src != '.') ||
00212 (*src > '9' &&
00213 *src < 'A') ||
00214 (*src > 'Z' &&
00215 *src < 'a' &&
00216 *src != '_') ||
00217 (*src > 'z')) {
00218 *dest++ = '%';
00219 *dest++ = hex[(*src >> 4) & 0x0f];
00220 *dest++ = hex[*src & 0x0f];
00221 max_dest_len -= 3;
00222 } else {
00223 *dest++ = *src;
00224 max_dest_len--;
00225 }
00226 }
00227
00228 *dest++ = '\0';
00229 max_dest_len--;
00230
00231 return max_dest_len;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 static const char *smbc_prefix = "smb:";
00272
00273 static int
00274 smbc_parse_path(SMBCCTX *context,
00275 const char *fname,
00276 char *workgroup, int workgroup_len,
00277 char *server, int server_len,
00278 char *share, int share_len,
00279 char *path, int path_len,
00280 char *user, int user_len,
00281 char *password, int password_len,
00282 char *options, int options_len)
00283 {
00284 static pstring s;
00285 pstring userinfo;
00286 const char *p;
00287 char *q, *r;
00288 int len;
00289
00290 server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
00291
00292
00293
00294
00295
00296 if (workgroup != NULL) {
00297 strncpy(workgroup, context->workgroup, workgroup_len - 1);
00298 workgroup[workgroup_len - 1] = '\0';
00299 }
00300
00301 if (options != NULL && options_len > 0) {
00302 options[0] = (char)0;
00303 }
00304 pstrcpy(s, fname);
00305
00306
00307 len = strlen(smbc_prefix);
00308 if (strncmp(s,smbc_prefix,len) || (s[len] != '/' && s[len] != 0)) {
00309 return -1;
00310 }
00311
00312 p = s + len;
00313
00314
00315
00316 if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
00317
00318 DEBUG(1, ("Invalid path (does not begin with smb://"));
00319 return -1;
00320
00321 }
00322
00323 p += 2;
00324
00325
00326 if ((q = strrchr(p, '?')) != NULL ) {
00327
00328 *q++ = '\0';
00329
00330 DEBUG(4, ("Found options '%s'", q));
00331
00332
00333 if (options != NULL && options_len > 0) {
00334 safe_strcpy(options, q, options_len - 1);
00335 }
00336 }
00337
00338 if (*p == (char)0)
00339 goto decoding;
00340
00341 if (*p == '/') {
00342 int wl = strlen(context->workgroup);
00343
00344 if (wl > 16) {
00345 wl = 16;
00346 }
00347
00348 strncpy(server, context->workgroup, wl);
00349 server[wl] = '\0';
00350 return 0;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 q = strchr_m(p, '@');
00362 r = strchr_m(p, '/');
00363 if (q && (!r || q < r)) {
00364 pstring username, passwd, domain;
00365 const char *u = userinfo;
00366
00367 next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring));
00368
00369 username[0] = passwd[0] = domain[0] = 0;
00370
00371 if (strchr_m(u, ';')) {
00372
00373 next_token_no_ltrim(&u, domain, ";", sizeof(fstring));
00374
00375 }
00376
00377 if (strchr_m(u, ':')) {
00378
00379 next_token_no_ltrim(&u, username, ":", sizeof(fstring));
00380
00381 pstrcpy(passwd, u);
00382
00383 }
00384 else {
00385
00386 pstrcpy(username, u);
00387
00388 }
00389
00390 if (domain[0] && workgroup) {
00391 strncpy(workgroup, domain, workgroup_len - 1);
00392 workgroup[workgroup_len - 1] = '\0';
00393 }
00394
00395 if (username[0]) {
00396 strncpy(user, username, user_len - 1);
00397 user[user_len - 1] = '\0';
00398 }
00399
00400 if (passwd[0]) {
00401 strncpy(password, passwd, password_len - 1);
00402 password[password_len - 1] = '\0';
00403 }
00404
00405 }
00406
00407 if (!next_token(&p, server, "/", sizeof(fstring))) {
00408
00409 return -1;
00410
00411 }
00412
00413 if (*p == (char)0) goto decoding;
00414
00415 if (!next_token(&p, share, "/", sizeof(fstring))) {
00416
00417 return -1;
00418
00419 }
00420
00421
00422
00423
00424
00425 *path = '\0';
00426 if (*p != '\0') {
00427 *path = '/';
00428 safe_strcpy(path + 1, p, path_len - 2);
00429 }
00430
00431 all_string_sub(path, "/", "\\", 0);
00432
00433 decoding:
00434 (void) smbc_urldecode(path, path, path_len);
00435 (void) smbc_urldecode(server, server, server_len);
00436 (void) smbc_urldecode(share, share, share_len);
00437 (void) smbc_urldecode(user, user, user_len);
00438 (void) smbc_urldecode(password, password, password_len);
00439
00440 return 0;
00441 }
00442
00443
00444
00445
00446 static int
00447 smbc_check_options(char *server,
00448 char *share,
00449 char *path,
00450 char *options)
00451 {
00452 DEBUG(4, ("smbc_check_options(): server='%s' share='%s' "
00453 "path='%s' options='%s'\n",
00454 server, share, path, options));
00455
00456
00457 if (! *options) return 0;
00458
00459
00460 return -1;
00461 }
00462
00463
00464
00465
00466 static int
00467 smbc_errno(SMBCCTX *context,
00468 struct cli_state *c)
00469 {
00470 int ret = cli_errno(c);
00471
00472 if (cli_is_dos_error(c)) {
00473 uint8 eclass;
00474 uint32 ecode;
00475
00476 cli_dos_error(c, &eclass, &ecode);
00477
00478 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
00479 (int)eclass, (int)ecode, (int)ecode, ret));
00480 } else {
00481 NTSTATUS status;
00482
00483 status = cli_nt_error(c);
00484
00485 DEBUG(3,("smbc errno %s -> %d\n",
00486 nt_errstr(status), ret));
00487 }
00488
00489 return ret;
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499 static int
00500 smbc_check_server(SMBCCTX * context,
00501 SMBCSRV * server)
00502 {
00503 socklen_t size;
00504 struct sockaddr addr;
00505
00506 size = sizeof(addr);
00507 return (getpeername(server->cli->fd, &addr, &size) == -1);
00508 }
00509
00510
00511
00512
00513
00514
00515
00516 int
00517 smbc_remove_unused_server(SMBCCTX * context,
00518 SMBCSRV * srv)
00519 {
00520 SMBCFILE * file;
00521
00522
00523 if (!context || !context->internal ||
00524 !context->internal->_initialized || !srv) return 1;
00525
00526
00527
00528 for (file = context->internal->_files; file; file=file->next) {
00529 if (file->srv == srv) {
00530
00531 DEBUG(3, ("smbc_remove_usused_server: "
00532 "%p still used by %p.\n",
00533 srv, file));
00534 return 1;
00535 }
00536 }
00537
00538 DLIST_REMOVE(context->internal->_servers, srv);
00539
00540 cli_shutdown(srv->cli);
00541 srv->cli = NULL;
00542
00543 DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv));
00544
00545 (context->callbacks.remove_cached_srv_fn)(context, srv);
00546
00547 SAFE_FREE(srv);
00548
00549 return 0;
00550 }
00551
00552 static SMBCSRV *
00553 find_server(SMBCCTX *context,
00554 const char *server,
00555 const char *share,
00556 fstring workgroup,
00557 fstring username,
00558 fstring password)
00559 {
00560 SMBCSRV *srv;
00561 int auth_called = 0;
00562
00563 check_server_cache:
00564
00565 srv = (context->callbacks.get_cached_srv_fn)(context, server, share,
00566 workgroup, username);
00567
00568 if (!auth_called && !srv && (!username[0] || !password[0])) {
00569 if (context->internal->_auth_fn_with_context != NULL) {
00570 (context->internal->_auth_fn_with_context)(
00571 context,
00572 server, share,
00573 workgroup, sizeof(fstring),
00574 username, sizeof(fstring),
00575 password, sizeof(fstring));
00576 } else {
00577 (context->callbacks.auth_fn)(
00578 server, share,
00579 workgroup, sizeof(fstring),
00580 username, sizeof(fstring),
00581 password, sizeof(fstring));
00582 }
00583
00584
00585
00586
00587
00588
00589 auth_called = 1;
00590 goto check_server_cache;
00591
00592 }
00593
00594 if (srv) {
00595 if ((context->callbacks.check_server_fn)(context, srv)) {
00596
00597
00598
00599
00600
00601 if ((context->callbacks.remove_unused_server_fn)(context,
00602 srv)) {
00603
00604
00605
00606
00607
00608
00609 (context->callbacks.remove_cached_srv_fn)(context,
00610 srv);
00611 }
00612
00613
00614
00615
00616
00617 goto check_server_cache;
00618 }
00619
00620 return srv;
00621 }
00622
00623 return NULL;
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 static SMBCSRV *
00638 smbc_server(SMBCCTX *context,
00639 BOOL connect_if_not_found,
00640 const char *server,
00641 const char *share,
00642 fstring workgroup,
00643 fstring username,
00644 fstring password)
00645 {
00646 SMBCSRV *srv=NULL;
00647 struct cli_state *c;
00648 struct nmb_name called, calling;
00649 const char *server_n = server;
00650 pstring ipenv;
00651 struct in_addr ip;
00652 int tried_reverse = 0;
00653 int port_try_first;
00654 int port_try_next;
00655 const char *username_used;
00656 NTSTATUS status;
00657
00658 zero_ip(&ip);
00659 ZERO_STRUCT(c);
00660
00661 if (server[0] == 0) {
00662 errno = EPERM;
00663 return NULL;
00664 }
00665
00666
00667 srv = find_server(context, server, share,
00668 workgroup, username, password);
00669
00670
00671
00672
00673
00674 if (srv && *share != '\0' && context->options.one_share_per_server) {
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 if (srv->cli->cnum == (uint16) -1) {
00685
00686 if (context->internal->_auth_fn_with_context != NULL) {
00687 (context->internal->_auth_fn_with_context)(
00688 context,
00689 server, share,
00690 workgroup, sizeof(fstring),
00691 username, sizeof(fstring),
00692 password, sizeof(fstring));
00693 } else {
00694 (context->callbacks.auth_fn)(
00695 server, share,
00696 workgroup, sizeof(fstring),
00697 username, sizeof(fstring),
00698 password, sizeof(fstring));
00699 }
00700
00701 if (! cli_send_tconX(srv->cli, share, "?????",
00702 password, strlen(password)+1)) {
00703
00704 errno = smbc_errno(context, srv->cli);
00705 cli_shutdown(srv->cli);
00706 srv->cli = NULL;
00707 (context->callbacks.remove_cached_srv_fn)(context,
00708 srv);
00709 srv = NULL;
00710 }
00711
00712
00713
00714
00715
00716 if (srv) {
00717 srv->dev = (dev_t)(str_checksum(server) ^
00718 str_checksum(share));
00719 }
00720 }
00721 }
00722
00723
00724 if (srv) {
00725
00726
00727 return srv;
00728 }
00729
00730
00731 if (! connect_if_not_found) {
00732
00733 return NULL;
00734 }
00735
00736 make_nmb_name(&calling, context->netbios_name, 0x0);
00737 make_nmb_name(&called , server, 0x20);
00738
00739 DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
00740
00741 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
00742
00743 again:
00744 slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
00745
00746 zero_ip(&ip);
00747
00748
00749 if ((c = cli_initialise()) == NULL) {
00750 errno = ENOMEM;
00751 return NULL;
00752 }
00753
00754 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
00755 c->use_kerberos = True;
00756 }
00757 if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) {
00758 c->fallback_after_kerberos = True;
00759 }
00760
00761 c->timeout = context->timeout;
00762
00763
00764
00765
00766
00767 if (share == NULL || *share == '\0' || strcmp(share, "IPC$") == 0) {
00768 port_try_first = 139;
00769 port_try_next = 445;
00770 } else {
00771 port_try_first = 445;
00772 port_try_next = 139;
00773 }
00774
00775 c->port = port_try_first;
00776
00777 status = cli_connect(c, server_n, &ip);
00778 if (!NT_STATUS_IS_OK(status)) {
00779
00780
00781 c->port = port_try_next;
00782
00783 status = cli_connect(c, server_n, &ip);
00784 if (!NT_STATUS_IS_OK(status)) {
00785 cli_shutdown(c);
00786 errno = ETIMEDOUT;
00787 return NULL;
00788 }
00789 }
00790
00791 if (!cli_session_request(c, &calling, &called)) {
00792 cli_shutdown(c);
00793 if (strcmp(called.name, "*SMBSERVER")) {
00794 make_nmb_name(&called , "*SMBSERVER", 0x20);
00795 goto again;
00796 } else {
00797
00798
00799
00800 if (is_ipaddress(server) && !tried_reverse) {
00801 fstring remote_name;
00802 struct in_addr rem_ip;
00803
00804 if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) {
00805 DEBUG(4, ("Could not convert IP address "
00806 "%s to struct in_addr\n", server));
00807 errno = ETIMEDOUT;
00808 return NULL;
00809 }
00810
00811 tried_reverse++;
00812
00813 if (name_status_find("*", 0, 0, rem_ip, remote_name)) {
00814 make_nmb_name(&called, remote_name, 0x20);
00815 goto again;
00816 }
00817 }
00818 }
00819 errno = ETIMEDOUT;
00820 return NULL;
00821 }
00822
00823 DEBUG(4,(" session request ok\n"));
00824
00825 if (!cli_negprot(c)) {
00826 cli_shutdown(c);
00827 errno = ETIMEDOUT;
00828 return NULL;
00829 }
00830
00831 username_used = username;
00832
00833 if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
00834 password, strlen(password),
00835 password, strlen(password),
00836 workgroup))) {
00837
00838
00839 username_used = "";
00840
00841 if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) ||
00842 !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
00843 password, 1,
00844 password, 0,
00845 workgroup))) {
00846
00847 cli_shutdown(c);
00848 errno = EPERM;
00849 return NULL;
00850 }
00851 }
00852
00853 DEBUG(4,(" session setup ok\n"));
00854
00855 if (!cli_send_tconX(c, share, "?????",
00856 password, strlen(password)+1)) {
00857 errno = smbc_errno(context, c);
00858 cli_shutdown(c);
00859 return NULL;
00860 }
00861
00862 DEBUG(4,(" tconx ok\n"));
00863
00864
00865
00866
00867
00868
00869 srv = SMB_MALLOC_P(SMBCSRV);
00870 if (!srv) {
00871 errno = ENOMEM;
00872 goto failed;
00873 }
00874
00875 ZERO_STRUCTP(srv);
00876 srv->cli = c;
00877 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
00878 srv->no_pathinfo = False;
00879 srv->no_pathinfo2 = False;
00880 srv->no_nt_session = False;
00881
00882
00883
00884 errno = 0;
00885 if ((context->callbacks.add_cached_srv_fn)(context, srv,
00886 server, share,
00887 workgroup, username)) {
00888 int saved_errno = errno;
00889 DEBUG(3, (" Failed to add server to cache\n"));
00890 errno = saved_errno;
00891 if (errno == 0) {
00892 errno = ENOMEM;
00893 }
00894 goto failed;
00895 }
00896
00897 DEBUG(2, ("Server connect ok: //%s/%s: %p\n",
00898 server, share, srv));
00899
00900 DLIST_ADD(context->internal->_servers, srv);
00901 return srv;
00902
00903 failed:
00904 cli_shutdown(c);
00905 if (!srv) {
00906 return NULL;
00907 }
00908
00909 SAFE_FREE(srv);
00910 return NULL;
00911 }
00912
00913
00914
00915
00916
00917 static SMBCSRV *
00918 smbc_attr_server(SMBCCTX *context,
00919 const char *server,
00920 const char *share,
00921 fstring workgroup,
00922 fstring username,
00923 fstring password,
00924 POLICY_HND *pol)
00925 {
00926 int flags;
00927 struct in_addr ip;
00928 struct cli_state *ipc_cli;
00929 struct rpc_pipe_client *pipe_hnd;
00930 NTSTATUS nt_status;
00931 SMBCSRV *ipc_srv=NULL;
00932
00933
00934
00935
00936
00937
00938 ipc_srv = find_server(context, server, "*IPC$",
00939 workgroup, username, password);
00940 if (!ipc_srv) {
00941
00942
00943 if (*password == '\0') {
00944
00945 if (context->internal->_auth_fn_with_context != NULL) {
00946 (context->internal->_auth_fn_with_context)(
00947 context,
00948 server, share,
00949 workgroup, sizeof(fstring),
00950 username, sizeof(fstring),
00951 password, sizeof(fstring));
00952 } else {
00953 (context->callbacks.auth_fn)(
00954 server, share,
00955 workgroup, sizeof(fstring),
00956 username, sizeof(fstring),
00957 password, sizeof(fstring));
00958 }
00959 }
00960
00961 flags = 0;
00962 if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
00963 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
00964 }
00965
00966 zero_ip(&ip);
00967 nt_status = cli_full_connection(&ipc_cli,
00968 global_myname(), server,
00969 &ip, 0, "IPC$", "?????",
00970 username, workgroup,
00971 password, flags,
00972 Undefined, NULL);
00973 if (! NT_STATUS_IS_OK(nt_status)) {
00974 DEBUG(1,("cli_full_connection failed! (%s)\n",
00975 nt_errstr(nt_status)));
00976 errno = ENOTSUP;
00977 return NULL;
00978 }
00979
00980 ipc_srv = SMB_MALLOC_P(SMBCSRV);
00981 if (!ipc_srv) {
00982 errno = ENOMEM;
00983 cli_shutdown(ipc_cli);
00984 return NULL;
00985 }
00986
00987 ZERO_STRUCTP(ipc_srv);
00988 ipc_srv->cli = ipc_cli;
00989
00990 if (pol) {
00991 pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli,
00992 PI_LSARPC,
00993 &nt_status);
00994 if (!pipe_hnd) {
00995 DEBUG(1, ("cli_nt_session_open fail!\n"));
00996 errno = ENOTSUP;
00997 cli_shutdown(ipc_srv->cli);
00998 free(ipc_srv);
00999 return NULL;
01000 }
01001
01002
01003
01004
01005
01006
01007
01008 nt_status = rpccli_lsa_open_policy(
01009 pipe_hnd,
01010 ipc_srv->cli->mem_ctx,
01011 True,
01012 GENERIC_EXECUTE_ACCESS,
01013 pol);
01014
01015 if (!NT_STATUS_IS_OK(nt_status)) {
01016 errno = smbc_errno(context, ipc_srv->cli);
01017 cli_shutdown(ipc_srv->cli);
01018 return NULL;
01019 }
01020 }
01021
01022
01023
01024 errno = 0;
01025 if ((context->callbacks.add_cached_srv_fn)(context, ipc_srv,
01026 server,
01027 "*IPC$",
01028 workgroup,
01029 username)) {
01030 DEBUG(3, (" Failed to add server to cache\n"));
01031 if (errno == 0) {
01032 errno = ENOMEM;
01033 }
01034 cli_shutdown(ipc_srv->cli);
01035 free(ipc_srv);
01036 return NULL;
01037 }
01038
01039 DLIST_ADD(context->internal->_servers, ipc_srv);
01040 }
01041
01042 return ipc_srv;
01043 }
01044
01045
01046
01047
01048
01049 static SMBCFILE *
01050 smbc_open_ctx(SMBCCTX *context,
01051 const char *fname,
01052 int flags,
01053 mode_t mode)
01054 {
01055 fstring server, share, user, password, workgroup;
01056 pstring path;
01057 pstring targetpath;
01058 struct cli_state *targetcli;
01059 SMBCSRV *srv = NULL;
01060 SMBCFILE *file = NULL;
01061 int fd;
01062
01063 if (!context || !context->internal ||
01064 !context->internal->_initialized) {
01065
01066 errno = EINVAL;
01067 return NULL;
01068
01069 }
01070
01071 if (!fname) {
01072
01073 errno = EINVAL;
01074 return NULL;
01075
01076 }
01077
01078 if (smbc_parse_path(context, fname,
01079 workgroup, sizeof(workgroup),
01080 server, sizeof(server),
01081 share, sizeof(share),
01082 path, sizeof(path),
01083 user, sizeof(user),
01084 password, sizeof(password),
01085 NULL, 0)) {
01086 errno = EINVAL;
01087 return NULL;
01088 }
01089
01090 if (user[0] == (char)0) fstrcpy(user, context->user);
01091
01092 srv = smbc_server(context, True,
01093 server, share, workgroup, user, password);
01094
01095 if (!srv) {
01096
01097 if (errno == EPERM) errno = EACCES;
01098 return NULL;
01099
01100 }
01101
01102
01103
01104 if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
01105
01106 fd = -1;
01107
01108 }
01109 else {
01110
01111 file = SMB_MALLOC_P(SMBCFILE);
01112
01113 if (!file) {
01114
01115 errno = ENOMEM;
01116 return NULL;
01117
01118 }
01119
01120 ZERO_STRUCTP(file);
01121
01122
01123 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
01124 {
01125 d_printf("Could not resolve %s\n", path);
01126 SAFE_FREE(file);
01127 return NULL;
01128 }
01129
01130
01131 if ((fd = cli_open(targetcli, targetpath, flags,
01132 context->internal->_share_mode)) < 0) {
01133
01134
01135
01136 SAFE_FREE(file);
01137 errno = smbc_errno(context, targetcli);
01138 return NULL;
01139
01140 }
01141
01142
01143
01144 file->cli_fd = fd;
01145 file->fname = SMB_STRDUP(fname);
01146 file->srv = srv;
01147 file->offset = 0;
01148 file->file = True;
01149
01150 DLIST_ADD(context->internal->_files, file);
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174 if (flags & O_APPEND) {
01175 if (smbc_lseek_ctx(context, file, 0, SEEK_END) < 0) {
01176 (void) smbc_close_ctx(context, file);
01177 errno = ENXIO;
01178 return NULL;
01179 }
01180 }
01181
01182 return file;
01183
01184 }
01185
01186
01187
01188 if (fd == -1) {
01189 int eno = 0;
01190
01191 eno = smbc_errno(context, srv->cli);
01192 file = (context->opendir)(context, fname);
01193 if (!file) errno = eno;
01194 return file;
01195
01196 }
01197
01198 errno = EINVAL;
01199 return NULL;
01200
01201 }
01202
01203
01204
01205
01206
01207 static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC;
01208
01209 static SMBCFILE *
01210 smbc_creat_ctx(SMBCCTX *context,
01211 const char *path,
01212 mode_t mode)
01213 {
01214
01215 if (!context || !context->internal ||
01216 !context->internal->_initialized) {
01217
01218 errno = EINVAL;
01219 return NULL;
01220
01221 }
01222
01223 return smbc_open_ctx(context, path, creat_bits, mode);
01224 }
01225
01226
01227
01228
01229
01230 static ssize_t
01231 smbc_read_ctx(SMBCCTX *context,
01232 SMBCFILE *file,
01233 void *buf,
01234 size_t count)
01235 {
01236 int ret;
01237 fstring server, share, user, password;
01238 pstring path, targetpath;
01239 struct cli_state *targetcli;
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 off_t offset;
01251
01252 if (!context || !context->internal ||
01253 !context->internal->_initialized) {
01254
01255 errno = EINVAL;
01256 return -1;
01257
01258 }
01259
01260 DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));
01261
01262 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
01263
01264 errno = EBADF;
01265 return -1;
01266
01267 }
01268
01269 offset = file->offset;
01270
01271
01272
01273 if (buf == NULL) {
01274
01275 errno = EINVAL;
01276 return -1;
01277
01278 }
01279
01280
01281 if (smbc_parse_path(context, file->fname,
01282 NULL, 0,
01283 server, sizeof(server),
01284 share, sizeof(share),
01285 path, sizeof(path),
01286 user, sizeof(user),
01287 password, sizeof(password),
01288 NULL, 0)) {
01289 errno = EINVAL;
01290 return -1;
01291 }
01292
01293
01294 if (!cli_resolve_path("", file->srv->cli, path,
01295 &targetcli, targetpath))
01296 {
01297 d_printf("Could not resolve %s\n", path);
01298 return -1;
01299 }
01300
01301
01302 ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count);
01303
01304 if (ret < 0) {
01305
01306 errno = smbc_errno(context, targetcli);
01307 return -1;
01308
01309 }
01310
01311 file->offset += ret;
01312
01313 DEBUG(4, (" --> %d\n", ret));
01314
01315 return ret;
01316
01317 }
01318
01319
01320
01321
01322
01323 static ssize_t
01324 smbc_write_ctx(SMBCCTX *context,
01325 SMBCFILE *file,
01326 void *buf,
01327 size_t count)
01328 {
01329 int ret;
01330 off_t offset;
01331 fstring server, share, user, password;
01332 pstring path, targetpath;
01333 struct cli_state *targetcli;
01334
01335
01336
01337 if (!context || !context->internal ||
01338 !context->internal->_initialized) {
01339
01340 errno = EINVAL;
01341 return -1;
01342
01343 }
01344
01345 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
01346
01347 errno = EBADF;
01348 return -1;
01349
01350 }
01351
01352
01353
01354 if (buf == NULL) {
01355
01356 errno = EINVAL;
01357 return -1;
01358
01359 }
01360
01361 offset = file->offset;
01362
01363
01364 if (smbc_parse_path(context, file->fname,
01365 NULL, 0,
01366 server, sizeof(server),
01367 share, sizeof(share),
01368 path, sizeof(path),
01369 user, sizeof(user),
01370 password, sizeof(password),
01371 NULL, 0)) {
01372 errno = EINVAL;
01373 return -1;
01374 }
01375
01376
01377 if (!cli_resolve_path("", file->srv->cli, path,
01378 &targetcli, targetpath))
01379 {
01380 d_printf("Could not resolve %s\n", path);
01381 return -1;
01382 }
01383
01384
01385
01386 ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count);
01387
01388 if (ret <= 0) {
01389
01390 errno = smbc_errno(context, targetcli);
01391 return -1;
01392
01393 }
01394
01395 file->offset += ret;
01396
01397 return ret;
01398 }
01399
01400
01401
01402
01403
01404 static int
01405 smbc_close_ctx(SMBCCTX *context,
01406 SMBCFILE *file)
01407 {
01408 SMBCSRV *srv;
01409 fstring server, share, user, password;
01410 pstring path, targetpath;
01411 struct cli_state *targetcli;
01412
01413 if (!context || !context->internal ||
01414 !context->internal->_initialized) {
01415
01416 errno = EINVAL;
01417 return -1;
01418
01419 }
01420
01421 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
01422
01423 errno = EBADF;
01424 return -1;
01425
01426 }
01427
01428
01429 if (!file->file) {
01430
01431 return (context->closedir)(context, file);
01432
01433 }
01434
01435
01436 if (smbc_parse_path(context, file->fname,
01437 NULL, 0,
01438 server, sizeof(server),
01439 share, sizeof(share),
01440 path, sizeof(path),
01441 user, sizeof(user),
01442 password, sizeof(password),
01443 NULL, 0)) {
01444 errno = EINVAL;
01445 return -1;
01446 }
01447
01448
01449 if (!cli_resolve_path("", file->srv->cli, path,
01450 &targetcli, targetpath))
01451 {
01452 d_printf("Could not resolve %s\n", path);
01453 return -1;
01454 }
01455
01456
01457 if (!cli_close(targetcli, file->cli_fd)) {
01458
01459 DEBUG(3, ("cli_close failed on %s. purging server.\n",
01460 file->fname));
01461
01462
01463 errno = smbc_errno(context, targetcli);
01464 srv = file->srv;
01465 DLIST_REMOVE(context->internal->_files, file);
01466 SAFE_FREE(file->fname);
01467 SAFE_FREE(file);
01468 (context->callbacks.remove_unused_server_fn)(context, srv);
01469
01470 return -1;
01471
01472 }
01473
01474 DLIST_REMOVE(context->internal->_files, file);
01475 SAFE_FREE(file->fname);
01476 SAFE_FREE(file);
01477
01478 return 0;
01479 }
01480
01481
01482
01483
01484
01485 static BOOL
01486 smbc_getatr(SMBCCTX * context,
01487 SMBCSRV *srv,
01488 char *path,
01489 uint16 *mode,
01490 SMB_OFF_T *size,
01491 struct timespec *create_time_ts,
01492 struct timespec *access_time_ts,
01493 struct timespec *write_time_ts,
01494 struct timespec *change_time_ts,
01495 SMB_INO_T *ino)
01496 {
01497 pstring fixedpath;
01498 pstring targetpath;
01499 struct cli_state *targetcli;
01500 time_t write_time;
01501
01502 if (!context || !context->internal ||
01503 !context->internal->_initialized) {
01504
01505 errno = EINVAL;
01506 return -1;
01507
01508 }
01509
01510
01511 if (strequal(path, ".") || strequal(path, ".."))
01512 pstrcpy(fixedpath, "\\");
01513 else
01514 {
01515 pstrcpy(fixedpath, path);
01516 trim_string(fixedpath, NULL, "\\..");
01517 trim_string(fixedpath, NULL, "\\.");
01518 }
01519 DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
01520
01521 if (!cli_resolve_path( "", srv->cli, fixedpath, &targetcli, targetpath))
01522 {
01523 d_printf("Couldn't resolve %s\n", path);
01524 return False;
01525 }
01526
01527 if (!srv->no_pathinfo2 &&
01528 cli_qpathinfo2(targetcli, targetpath,
01529 create_time_ts,
01530 access_time_ts,
01531 write_time_ts,
01532 change_time_ts,
01533 size, mode, ino)) {
01534 return True;
01535 }
01536
01537
01538 if (targetcli->capabilities & CAP_NT_SMBS) {
01539 errno = EPERM;
01540 return False;
01541 }
01542
01543 if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) {
01544
01545 struct timespec w_time_ts;
01546
01547 w_time_ts = convert_time_t_to_timespec(write_time);
01548
01549 if (write_time_ts != NULL) {
01550 *write_time_ts = w_time_ts;
01551 }
01552
01553 if (create_time_ts != NULL) {
01554 *create_time_ts = w_time_ts;
01555 }
01556
01557 if (access_time_ts != NULL) {
01558 *access_time_ts = w_time_ts;
01559 }
01560
01561 if (change_time_ts != NULL) {
01562 *change_time_ts = w_time_ts;
01563 }
01564
01565 srv->no_pathinfo2 = True;
01566 return True;
01567 }
01568
01569 errno = EPERM;
01570 return False;
01571
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584 static BOOL
01585 smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
01586 time_t create_time,
01587 time_t access_time,
01588 time_t write_time,
01589 time_t change_time,
01590 uint16 mode)
01591 {
01592 int fd;
01593 int ret;
01594
01595
01596
01597
01598
01599
01600
01601 if (srv->no_pathinfo ||
01602 ! cli_setpathinfo(srv->cli, path,
01603 create_time,
01604 access_time,
01605 write_time,
01606 change_time,
01607 mode)) {
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620 srv->no_pathinfo = True;
01621
01622
01623 if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
01624
01625 errno = smbc_errno(context, srv->cli);
01626 return -1;
01627 }
01628
01629
01630 ret = cli_setattrE(srv->cli, fd,
01631 change_time,
01632 access_time,
01633 write_time);
01634
01635
01636 cli_close(srv->cli, fd);
01637
01638
01639
01640
01641
01642
01643
01644 if (ret && mode != (uint16) -1) {
01645 ret = cli_setatr(srv->cli, path, mode, 0);
01646 }
01647
01648 if (! ret) {
01649 errno = smbc_errno(context, srv->cli);
01650 return False;
01651 }
01652 }
01653
01654 return True;
01655 }
01656
01657
01658
01659
01660
01661 static int
01662 smbc_unlink_ctx(SMBCCTX *context,
01663 const char *fname)
01664 {
01665 fstring server, share, user, password, workgroup;
01666 pstring path, targetpath;
01667 struct cli_state *targetcli;
01668 SMBCSRV *srv = NULL;
01669
01670 if (!context || !context->internal ||
01671 !context->internal->_initialized) {
01672
01673 errno = EINVAL;
01674 return -1;
01675
01676 }
01677
01678 if (!fname) {
01679
01680 errno = EINVAL;
01681 return -1;
01682
01683 }
01684
01685 if (smbc_parse_path(context, fname,
01686 workgroup, sizeof(workgroup),
01687 server, sizeof(server),
01688 share, sizeof(share),
01689 path, sizeof(path),
01690 user, sizeof(user),
01691 password, sizeof(password),
01692 NULL, 0)) {
01693 errno = EINVAL;
01694 return -1;
01695 }
01696
01697 if (user[0] == (char)0) fstrcpy(user, context->user);
01698
01699 srv = smbc_server(context, True,
01700 server, share, workgroup, user, password);
01701
01702 if (!srv) {
01703
01704 return -1;
01705
01706 }
01707
01708
01709 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
01710 {
01711 d_printf("Could not resolve %s\n", path);
01712 return -1;
01713 }
01714
01715
01716 if (!cli_unlink(targetcli, targetpath)) {
01717
01718 errno = smbc_errno(context, targetcli);
01719
01720 if (errno == EACCES) {
01721
01722 int saverr = errno;
01723 SMB_OFF_T size = 0;
01724 uint16 mode = 0;
01725 struct timespec write_time_ts;
01726 struct timespec access_time_ts;
01727 struct timespec change_time_ts;
01728 SMB_INO_T ino = 0;
01729
01730 if (!smbc_getatr(context, srv, path, &mode, &size,
01731 NULL,
01732 &access_time_ts,
01733 &write_time_ts,
01734 &change_time_ts,
01735 &ino)) {
01736
01737
01738
01739 errno = smbc_errno(context, targetcli);
01740 return -1;
01741
01742 }
01743 else {
01744
01745 if (IS_DOS_DIR(mode))
01746 errno = EISDIR;
01747 else
01748 errno = saverr;
01749
01750 }
01751 }
01752
01753 return -1;
01754
01755 }
01756
01757 return 0;
01758
01759 }
01760
01761
01762
01763
01764
01765 static int
01766 smbc_rename_ctx(SMBCCTX *ocontext,
01767 const char *oname,
01768 SMBCCTX *ncontext,
01769 const char *nname)
01770 {
01771 fstring server1;
01772 fstring share1;
01773 fstring server2;
01774 fstring share2;
01775 fstring user1;
01776 fstring user2;
01777 fstring password1;
01778 fstring password2;
01779 fstring workgroup;
01780 pstring path1;
01781 pstring path2;
01782 pstring targetpath1;
01783 pstring targetpath2;
01784 struct cli_state *targetcli1;
01785 struct cli_state *targetcli2;
01786 SMBCSRV *srv = NULL;
01787
01788 if (!ocontext || !ncontext ||
01789 !ocontext->internal || !ncontext->internal ||
01790 !ocontext->internal->_initialized ||
01791 !ncontext->internal->_initialized) {
01792
01793 errno = EINVAL;
01794 return -1;
01795
01796 }
01797
01798 if (!oname || !nname) {
01799
01800 errno = EINVAL;
01801 return -1;
01802
01803 }
01804
01805 DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
01806
01807 smbc_parse_path(ocontext, oname,
01808 workgroup, sizeof(workgroup),
01809 server1, sizeof(server1),
01810 share1, sizeof(share1),
01811 path1, sizeof(path1),
01812 user1, sizeof(user1),
01813 password1, sizeof(password1),
01814 NULL, 0);
01815
01816 if (user1[0] == (char)0) fstrcpy(user1, ocontext->user);
01817
01818 smbc_parse_path(ncontext, nname,
01819 NULL, 0,
01820 server2, sizeof(server2),
01821 share2, sizeof(share2),
01822 path2, sizeof(path2),
01823 user2, sizeof(user2),
01824 password2, sizeof(password2),
01825 NULL, 0);
01826
01827 if (user2[0] == (char)0) fstrcpy(user2, ncontext->user);
01828
01829 if (strcmp(server1, server2) || strcmp(share1, share2) ||
01830 strcmp(user1, user2)) {
01831
01832
01833
01834 errno = EXDEV;
01835 return -1;
01836
01837 }
01838
01839 srv = smbc_server(ocontext, True,
01840 server1, share1, workgroup, user1, password1);
01841 if (!srv) {
01842
01843 return -1;
01844
01845 }
01846
01847
01848 if (!cli_resolve_path( "", srv->cli, path1, &targetcli1, targetpath1))
01849 {
01850 d_printf("Could not resolve %s\n", path1);
01851 return -1;
01852 }
01853
01854
01855 if (!cli_resolve_path( "", srv->cli, path2, &targetcli2, targetpath2))
01856 {
01857 d_printf("Could not resolve %s\n", path2);
01858 return -1;
01859 }
01860
01861
01862 if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
01863 strcmp(targetcli1->share, targetcli2->share))
01864 {
01865
01866
01867 errno = EXDEV;
01868 return -1;
01869 }
01870
01871 if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
01872 int eno = smbc_errno(ocontext, targetcli1);
01873
01874 if (eno != EEXIST ||
01875 !cli_unlink(targetcli1, targetpath2) ||
01876 !cli_rename(targetcli1, targetpath1, targetpath2)) {
01877
01878 errno = eno;
01879 return -1;
01880
01881 }
01882 }
01883
01884 return 0;
01885
01886 }
01887
01888
01889
01890
01891
01892 static off_t
01893 smbc_lseek_ctx(SMBCCTX *context,
01894 SMBCFILE *file,
01895 off_t offset,
01896 int whence)
01897 {
01898 SMB_OFF_T size;
01899 fstring server, share, user, password;
01900 pstring path, targetpath;
01901 struct cli_state *targetcli;
01902
01903 if (!context || !context->internal ||
01904 !context->internal->_initialized) {
01905
01906 errno = EINVAL;
01907 return -1;
01908
01909 }
01910
01911 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
01912
01913 errno = EBADF;
01914 return -1;
01915
01916 }
01917
01918 if (!file->file) {
01919
01920 errno = EINVAL;
01921 return -1;
01922
01923 }
01924
01925 switch (whence) {
01926 case SEEK_SET:
01927 file->offset = offset;
01928 break;
01929
01930 case SEEK_CUR:
01931 file->offset += offset;
01932 break;
01933
01934 case SEEK_END:
01935
01936 if (smbc_parse_path(context, file->fname,
01937 NULL, 0,
01938 server, sizeof(server),
01939 share, sizeof(share),
01940 path, sizeof(path),
01941 user, sizeof(user),
01942 password, sizeof(password),
01943 NULL, 0)) {
01944
01945 errno = EINVAL;
01946 return -1;
01947 }
01948
01949
01950 if (!cli_resolve_path("", file->srv->cli, path,
01951 &targetcli, targetpath))
01952 {
01953 d_printf("Could not resolve %s\n", path);
01954 return -1;
01955 }
01956
01957
01958 if (!cli_qfileinfo(targetcli, file->cli_fd, NULL,
01959 &size, NULL, NULL, NULL, NULL, NULL))
01960 {
01961 SMB_OFF_T b_size = size;
01962 if (!cli_getattrE(targetcli, file->cli_fd,
01963 NULL, &b_size, NULL, NULL, NULL))
01964 {
01965 errno = EINVAL;
01966 return -1;
01967 } else
01968 size = b_size;
01969 }
01970 file->offset = size + offset;
01971 break;
01972
01973 default:
01974 errno = EINVAL;
01975 break;
01976
01977 }
01978
01979 return file->offset;
01980
01981 }
01982
01983
01984
01985
01986
01987 static ino_t
01988 smbc_inode(SMBCCTX *context,
01989 const char *name)
01990 {
01991
01992 if (!context || !context->internal ||
01993 !context->internal->_initialized) {
01994
01995 errno = EINVAL;
01996 return -1;
01997
01998 }
01999
02000 if (!*name) return 2;
02001 return (ino_t)str_checksum(name);
02002
02003 }
02004
02005
02006
02007
02008
02009
02010 static int
02011 smbc_setup_stat(SMBCCTX *context,
02012 struct stat *st,
02013 char *fname,
02014 SMB_OFF_T size,
02015 int mode)
02016 {
02017
02018 st->st_mode = 0;
02019
02020 if (IS_DOS_DIR(mode)) {
02021 st->st_mode = SMBC_DIR_MODE;
02022 } else {
02023 st->st_mode = SMBC_FILE_MODE;
02024 }
02025
02026 if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
02027 if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
02028 if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
02029 if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
02030
02031 st->st_size = size;
02032 #ifdef HAVE_STAT_ST_BLKSIZE
02033 st->st_blksize = 512;
02034 #endif
02035 #ifdef HAVE_STAT_ST_BLOCKS
02036 st->st_blocks = (size+511)/512;
02037 #endif
02038 st->st_uid = getuid();
02039 st->st_gid = getgid();
02040
02041 if (IS_DOS_DIR(mode)) {
02042 st->st_nlink = 2;
02043 } else {
02044 st->st_nlink = 1;
02045 }
02046
02047 if (st->st_ino == 0) {
02048 st->st_ino = smbc_inode(context, fname);
02049 }
02050
02051 return True;
02052
02053 }
02054
02055
02056
02057
02058
02059 static int
02060 smbc_stat_ctx(SMBCCTX *context,
02061 const char *fname,
02062 struct stat *st)
02063 {
02064 SMBCSRV *srv;
02065 fstring server;
02066 fstring share;
02067 fstring user;
02068 fstring password;
02069 fstring workgroup;
02070 pstring path;
02071 struct timespec write_time_ts;
02072 struct timespec access_time_ts;
02073 struct timespec change_time_ts;
02074 SMB_OFF_T size = 0;
02075 uint16 mode = 0;
02076 SMB_INO_T ino = 0;
02077
02078 if (!context || !context->internal ||
02079 !context->internal->_initialized) {
02080
02081 errno = EINVAL;
02082 return -1;
02083
02084 }
02085
02086 if (!fname) {
02087
02088 errno = EINVAL;
02089 return -1;
02090
02091 }
02092
02093 DEBUG(4, ("smbc_stat(%s)\n", fname));
02094
02095 if (smbc_parse_path(context, fname,
02096 workgroup, sizeof(workgroup),
02097 server, sizeof(server),
02098 share, sizeof(share),
02099 path, sizeof(path),
02100 user, sizeof(user),
02101 password, sizeof(password),
02102 NULL, 0)) {
02103 errno = EINVAL;
02104 return -1;
02105 }
02106
02107 if (user[0] == (char)0) fstrcpy(user, context->user);
02108
02109 srv = smbc_server(context, True,
02110 server, share, workgroup, user, password);
02111
02112 if (!srv) {
02113 return -1;
02114 }
02115
02116 if (!smbc_getatr(context, srv, path, &mode, &size,
02117 NULL,
02118 &access_time_ts,
02119 &write_time_ts,
02120 &change_time_ts,
02121 &ino)) {
02122
02123 errno = smbc_errno(context, srv->cli);
02124 return -1;
02125
02126 }
02127
02128 st->st_ino = ino;
02129
02130 smbc_setup_stat(context, st, path, size, mode);
02131
02132 set_atimespec(st, access_time_ts);
02133 set_ctimespec(st, change_time_ts);
02134 set_mtimespec(st, write_time_ts);
02135 st->st_dev = srv->dev;
02136
02137 return 0;
02138
02139 }
02140
02141
02142
02143
02144
02145 static int
02146 smbc_fstat_ctx(SMBCCTX *context,
02147 SMBCFILE *file,
02148 struct stat *st)
02149 {
02150 struct timespec change_time_ts;
02151 struct timespec access_time_ts;
02152 struct timespec write_time_ts;
02153 SMB_OFF_T size;
02154 uint16 mode;
02155 fstring server;
02156 fstring share;
02157 fstring user;
02158 fstring password;
02159 pstring path;
02160 pstring targetpath;
02161 struct cli_state *targetcli;
02162 SMB_INO_T ino = 0;
02163
02164 if (!context || !context->internal ||
02165 !context->internal->_initialized) {
02166
02167 errno = EINVAL;
02168 return -1;
02169
02170 }
02171
02172 if (!file || !DLIST_CONTAINS(context->internal->_files, file)) {
02173
02174 errno = EBADF;
02175 return -1;
02176
02177 }
02178
02179 if (!file->file) {
02180
02181 return (context->fstatdir)(context, file, st);
02182
02183 }
02184
02185
02186 if (smbc_parse_path(context, file->fname,
02187 NULL, 0,
02188 server, sizeof(server),
02189 share, sizeof(share),
02190 path, sizeof(path),
02191 user, sizeof(user),
02192 password, sizeof(password),
02193 NULL, 0)) {
02194 errno = EINVAL;
02195 return -1;
02196 }
02197
02198
02199 if (!cli_resolve_path("", file->srv->cli, path,
02200 &targetcli, targetpath))
02201 {
02202 d_printf("Could not resolve %s\n", path);
02203 return -1;
02204 }
02205
02206
02207 if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size,
02208 NULL,
02209 &access_time_ts,
02210 &write_time_ts,
02211 &change_time_ts,
02212 &ino)) {
02213
02214 time_t change_time, access_time, write_time;
02215
02216 if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size,
02217 &change_time, &access_time, &write_time)) {
02218
02219 errno = EINVAL;
02220 return -1;
02221 }
02222
02223 change_time_ts = convert_time_t_to_timespec(change_time);
02224 access_time_ts = convert_time_t_to_timespec(access_time);
02225 write_time_ts = convert_time_t_to_timespec(write_time);
02226 }
02227
02228 st->st_ino = ino;
02229
02230 smbc_setup_stat(context, st, file->fname, size, mode);
02231
02232 set_atimespec(st, access_time_ts);
02233 set_ctimespec(st, change_time_ts);
02234 set_mtimespec(st, write_time_ts);
02235 st->st_dev = file->srv->dev;
02236
02237 return 0;
02238
02239 }
02240
02241
02242
02243
02244
02245
02246 static void
02247 smbc_remove_dir(SMBCFILE *dir)
02248 {
02249 struct smbc_dir_list *d,*f;
02250
02251 d = dir->dir_list;
02252 while (d) {
02253
02254 f = d; d = d->next;
02255
02256 SAFE_FREE(f->dirent);
02257 SAFE_FREE(f);
02258
02259 }
02260
02261 dir->dir_list = dir->dir_end = dir->dir_next = NULL;
02262
02263 }
02264
02265 static int
02266 add_dirent(SMBCFILE *dir,
02267 const char *name,
02268 const char *comment,
02269 uint32 type)
02270 {
02271 struct smbc_dirent *dirent;
02272 int size;
02273 int name_length = (name == NULL ? 0 : strlen(name));
02274 int comment_len = (comment == NULL ? 0 : strlen(comment));
02275
02276
02277
02278
02279
02280
02281 size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
02282
02283 dirent = (struct smbc_dirent *)SMB_MALLOC(size);
02284
02285 if (!dirent) {
02286
02287 dir->dir_error = ENOMEM;
02288 return -1;
02289
02290 }
02291
02292 ZERO_STRUCTP(dirent);
02293
02294 if (dir->dir_list == NULL) {
02295
02296 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
02297 if (!dir->dir_list) {
02298
02299 SAFE_FREE(dirent);
02300 dir->dir_error = ENOMEM;
02301 return -1;
02302
02303 }
02304 ZERO_STRUCTP(dir->dir_list);
02305
02306 dir->dir_end = dir->dir_next = dir->dir_list;
02307 }
02308 else {
02309
02310 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
02311
02312 if (!dir->dir_end->next) {
02313
02314 SAFE_FREE(dirent);
02315 dir->dir_error = ENOMEM;
02316 return -1;
02317
02318 }
02319 ZERO_STRUCTP(dir->dir_end->next);
02320
02321 dir->dir_end = dir->dir_end->next;
02322 }
02323
02324 dir->dir_end->next = NULL;
02325 dir->dir_end->dirent = dirent;
02326
02327 dirent->smbc_type = type;
02328 dirent->namelen = name_length;
02329 dirent->commentlen = comment_len;
02330 dirent->dirlen = size;
02331
02332
02333
02334
02335
02336
02337 strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
02338 dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
02339 strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
02340
02341 return 0;
02342
02343 }
02344
02345 static void
02346 list_unique_wg_fn(const char *name,
02347 uint32 type,
02348 const char *comment,
02349 void *state)
02350 {
02351 SMBCFILE *dir = (SMBCFILE *)state;
02352 struct smbc_dir_list *dir_list;
02353 struct smbc_dirent *dirent;
02354 int dirent_type;
02355 int do_remove = 0;
02356
02357 dirent_type = dir->dir_type;
02358
02359 if (add_dirent(dir, name, comment, dirent_type) < 0) {
02360
02361
02362
02363 }
02364
02365
02366 dirent = dir->dir_end->dirent;
02367
02368
02369 for (dir_list = dir->dir_list;
02370 dir_list != dir->dir_end;
02371 dir_list = dir_list->next) {
02372 if (! do_remove &&
02373 strcmp(dir_list->dirent->name, dirent->name) == 0) {
02374
02375 do_remove = 1;
02376 }
02377
02378 if (do_remove && dir_list->next == dir->dir_end) {
02379
02380 dir->dir_end = dir_list;
02381 free(dir_list->next);
02382 free(dirent);
02383 dir_list->next = NULL;
02384 break;
02385 }
02386 }
02387 }
02388
02389 static void
02390 list_fn(const char *name,
02391 uint32 type,
02392 const char *comment,
02393 void *state)
02394 {
02395 SMBCFILE *dir = (SMBCFILE *)state;
02396 int dirent_type;
02397
02398
02399
02400
02401
02402
02403
02404
02405
02406
02407
02408
02409
02410 if (dir->dir_type == SMBC_FILE_SHARE) {
02411
02412 switch (type) {
02413 case 0 | 0x80000000:
02414 case 0:
02415 dirent_type = SMBC_FILE_SHARE;
02416 break;
02417
02418 case 1:
02419 dirent_type = SMBC_PRINTER_SHARE;
02420 break;
02421
02422 case 2:
02423 dirent_type = SMBC_COMMS_SHARE;
02424 break;
02425
02426 case 3 | 0x80000000:
02427 case 3:
02428 dirent_type = SMBC_IPC_SHARE;
02429 break;
02430
02431 default:
02432 dirent_type = SMBC_FILE_SHARE;
02433 break;
02434 }
02435 }
02436 else {
02437 dirent_type = dir->dir_type;
02438 }
02439
02440 if (add_dirent(dir, name, comment, dirent_type) < 0) {
02441
02442
02443
02444
02445 }
02446 }
02447
02448 static void
02449 dir_list_fn(const char *mnt,
02450 file_info *finfo,
02451 const char *mask,
02452 void *state)
02453 {
02454
02455 if (add_dirent((SMBCFILE *)state, finfo->name, "",
02456 (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
02457
02458
02459
02460
02461
02462 }
02463
02464 }
02465
02466 static int
02467 net_share_enum_rpc(struct cli_state *cli,
02468 void (*fn)(const char *name,
02469 uint32 type,
02470 const char *comment,
02471 void *state),
02472 void *state)
02473 {
02474 int i;
02475 WERROR result;
02476 ENUM_HND enum_hnd;
02477 uint32 info_level = 1;
02478 uint32 preferred_len = 0xffffffff;
02479 uint32 type;
02480 SRV_SHARE_INFO_CTR ctr;
02481 fstring name = "";
02482 fstring comment = "";
02483 void *mem_ctx;
02484 struct rpc_pipe_client *pipe_hnd;
02485 NTSTATUS nt_status;
02486
02487
02488 pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
02489 if (!pipe_hnd) {
02490 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
02491 return -1;
02492 }
02493
02494
02495 mem_ctx = talloc_init("libsmbclient: net_share_enum_rpc");
02496 if (mem_ctx == NULL) {
02497 DEBUG(0, ("out of memory for net_share_enum_rpc!\n"));
02498 cli_rpc_pipe_close(pipe_hnd);
02499 return -1;
02500 }
02501
02502
02503 init_enum_hnd(&enum_hnd, 0);
02504 result = rpccli_srvsvc_net_share_enum(pipe_hnd,
02505 mem_ctx,
02506 info_level,
02507 &ctr,
02508 preferred_len,
02509 &enum_hnd);
02510
02511
02512 if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
02513
02514 goto done;
02515 }
02516
02517
02518 for (i = 0; i < ctr.num_entries; i++) {
02519
02520
02521 rpcstr_pull_unistr2_fstring(
02522 name, &ctr.share.info1[i].info_1_str.uni_netname);
02523
02524
02525 rpcstr_pull_unistr2_fstring(
02526 comment, &ctr.share.info1[i].info_1_str.uni_remark);
02527
02528
02529 type = ctr.share.info1[i].info_1.type;
02530
02531
02532 (*fn)(name, type, comment, state);
02533 }
02534
02535 done:
02536
02537 cli_rpc_pipe_close(pipe_hnd);
02538
02539
02540 TALLOC_FREE(mem_ctx);
02541
02542
02543 return W_ERROR_IS_OK(result) ? 0 : -1;
02544 }
02545
02546
02547
02548 static SMBCFILE *
02549 smbc_opendir_ctx(SMBCCTX *context,
02550 const char *fname)
02551 {
02552 int saved_errno;
02553 fstring server, share, user, password, options;
02554 pstring workgroup;
02555 pstring path;
02556 uint16 mode;
02557 char *p;
02558 SMBCSRV *srv = NULL;
02559 SMBCFILE *dir = NULL;
02560 struct _smbc_callbacks *cb;
02561 struct in_addr rem_ip;
02562
02563 if (!context || !context->internal ||
02564 !context->internal->_initialized) {
02565 DEBUG(4, ("no valid context\n"));
02566 errno = EINVAL + 8192;
02567 return NULL;
02568
02569 }
02570
02571 if (!fname) {
02572 DEBUG(4, ("no valid fname\n"));
02573 errno = EINVAL + 8193;
02574 return NULL;
02575 }
02576
02577 if (smbc_parse_path(context, fname,
02578 workgroup, sizeof(workgroup),
02579 server, sizeof(server),
02580 share, sizeof(share),
02581 path, sizeof(path),
02582 user, sizeof(user),
02583 password, sizeof(password),
02584 options, sizeof(options))) {
02585 DEBUG(4, ("no valid path\n"));
02586 errno = EINVAL + 8194;
02587 return NULL;
02588 }
02589
02590 DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
02591 "path='%s' options='%s'\n",
02592 fname, server, share, path, options));
02593
02594
02595 if (smbc_check_options(server, share, path, options)) {
02596 DEBUG(4, ("unacceptable options (%s)\n", options));
02597 errno = EINVAL + 8195;
02598 return NULL;
02599 }
02600
02601 if (user[0] == (char)0) fstrcpy(user, context->user);
02602
02603 dir = SMB_MALLOC_P(SMBCFILE);
02604
02605 if (!dir) {
02606
02607 errno = ENOMEM;
02608 return NULL;
02609
02610 }
02611
02612 ZERO_STRUCTP(dir);
02613
02614 dir->cli_fd = 0;
02615 dir->fname = SMB_STRDUP(fname);
02616 dir->srv = NULL;
02617 dir->offset = 0;
02618 dir->file = False;
02619 dir->dir_list = dir->dir_next = dir->dir_end = NULL;
02620
02621 if (server[0] == (char)0) {
02622
02623 int i;
02624 int count;
02625 int max_lmb_count;
02626 struct ip_service *ip_list;
02627 struct ip_service server_addr;
02628 struct user_auth_info u_info;
02629 struct cli_state *cli;
02630
02631 if (share[0] != (char)0 || path[0] != (char)0) {
02632
02633 errno = EINVAL + 8196;
02634 if (dir) {
02635 SAFE_FREE(dir->fname);
02636 SAFE_FREE(dir);
02637 }
02638 return NULL;
02639 }
02640
02641
02642 max_lmb_count = (context->options.browse_max_lmb_count == 0
02643 ? INT_MAX
02644 : context->options.browse_max_lmb_count);
02645
02646 pstrcpy(u_info.username, user);
02647 pstrcpy(u_info.password, password);
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658 ip_list = NULL;
02659 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
02660
02661 SAFE_FREE(ip_list);
02662
02663 if (!find_master_ip(workgroup, &server_addr.ip)) {
02664
02665 if (dir) {
02666 SAFE_FREE(dir->fname);
02667 SAFE_FREE(dir);
02668 }
02669 errno = ENOENT;
02670 return NULL;
02671 }
02672
02673 ip_list = &server_addr;
02674 count = 1;
02675 }
02676
02677 for (i = 0; i < count && i < max_lmb_count; i++) {
02678 DEBUG(99, ("Found master browser %d of %d: %s\n",
02679 i+1, MAX(count, max_lmb_count),
02680 inet_ntoa(ip_list[i].ip)));
02681
02682 cli = get_ipc_connect_master_ip(&ip_list[i],
02683 workgroup, &u_info);
02684
02685
02686 if ( !cli )
02687 continue;
02688
02689 fstrcpy(server, cli->desthost);
02690 cli_shutdown(cli);
02691
02692 DEBUG(4, ("using workgroup %s %s\n",
02693 workgroup, server));
02694
02695
02696
02697
02698
02699
02700
02701
02702 srv = smbc_server(context, True, server, "IPC$",
02703 workgroup, user, password);
02704 if (!srv) {
02705 continue;
02706 }
02707
02708 dir->srv = srv;
02709 dir->dir_type = SMBC_WORKGROUP;
02710
02711
02712
02713 if (!cli_NetServerEnum(srv->cli,
02714 workgroup,
02715 SV_TYPE_DOMAIN_ENUM,
02716 list_unique_wg_fn,
02717 (void *)dir)) {
02718 continue;
02719 }
02720 }
02721
02722 SAFE_FREE(ip_list);
02723 } else {
02724
02725
02726
02727
02728 if (*share == '\0') {
02729 if (*path != '\0') {
02730
02731
02732 errno = EINVAL + 8197;
02733 if (dir) {
02734 SAFE_FREE(dir->fname);
02735 SAFE_FREE(dir);
02736 }
02737 return NULL;
02738
02739 }
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755 srv = smbc_server(context, False, server, "IPC$",
02756 workgroup, user, password);
02757
02758
02759
02760
02761
02762 if (!srv &&
02763 !is_ipaddress(server) &&
02764 (resolve_name(server, &rem_ip, 0x1d) ||
02765 resolve_name(server, &rem_ip, 0x1b) )) {
02766
02767 fstring buserver;
02768
02769 dir->dir_type = SMBC_SERVER;
02770
02771
02772
02773
02774 if (!name_status_find(server, 0, 0,
02775 rem_ip, buserver)) {
02776
02777 DEBUG(0, ("Could not get name of "
02778 "local/domain master browser "
02779 "for server %s\n", server));
02780 if (dir) {
02781 SAFE_FREE(dir->fname);
02782 SAFE_FREE(dir);
02783 }
02784 errno = EPERM;
02785 return NULL;
02786
02787 }
02788
02789
02790
02791
02792
02793 srv = smbc_server(context, True,
02794 buserver, "IPC$",
02795 workgroup, user, password);
02796 if (!srv) {
02797 DEBUG(0, ("got no contact to IPC$\n"));
02798 if (dir) {
02799 SAFE_FREE(dir->fname);
02800 SAFE_FREE(dir);
02801 }
02802 return NULL;
02803
02804 }
02805
02806 dir->srv = srv;
02807
02808
02809 if (!cli_NetServerEnum(srv->cli, server,
02810 0x0000FFFE, list_fn,
02811 (void *)dir)) {
02812
02813 if (dir) {
02814 SAFE_FREE(dir->fname);
02815 SAFE_FREE(dir);
02816 }
02817 return NULL;
02818 }
02819 } else if (srv ||
02820 (resolve_name(server, &rem_ip, 0x20))) {
02821
02822
02823 if (!srv) {
02824 srv = smbc_server(context, True,
02825 server, "IPC$",
02826 workgroup,
02827 user, password);
02828 }
02829
02830 if (!srv) {
02831 if (dir) {
02832 SAFE_FREE(dir->fname);
02833 SAFE_FREE(dir);
02834 }
02835 return NULL;
02836
02837 }
02838
02839 dir->dir_type = SMBC_FILE_SHARE;
02840 dir->srv = srv;
02841
02842
02843
02844 if (net_share_enum_rpc(
02845 srv->cli,
02846 list_fn,
02847 (void *) dir) < 0 &&
02848 cli_RNetShareEnum(
02849 srv->cli,
02850 list_fn,
02851 (void *)dir) < 0) {
02852
02853 errno = cli_errno(srv->cli);
02854 if (dir) {
02855 SAFE_FREE(dir->fname);
02856 SAFE_FREE(dir);
02857 }
02858 return NULL;
02859
02860 }
02861 } else {
02862
02863 errno = ECONNREFUSED;
02864 if (dir) {
02865 SAFE_FREE(dir->fname);
02866 SAFE_FREE(dir);
02867 }
02868 return NULL;
02869 }
02870
02871 }
02872 else {
02873
02874
02875
02876
02877 pstring targetpath;
02878 struct cli_state *targetcli;
02879
02880
02881 dir->dir_type = SMBC_FILE_SHARE;
02882
02883 srv = smbc_server(context, True, server, share,
02884 workgroup, user, password);
02885
02886 if (!srv) {
02887
02888 if (dir) {
02889 SAFE_FREE(dir->fname);
02890 SAFE_FREE(dir);
02891 }
02892 return NULL;
02893
02894 }
02895
02896 dir->srv = srv;
02897
02898
02899
02900 p = path + strlen(path);
02901 pstrcat(path, "\\*");
02902
02903 if (!cli_resolve_path("", srv->cli, path,
02904 &targetcli, targetpath))
02905 {
02906 d_printf("Could not resolve %s\n", path);
02907 if (dir) {
02908 SAFE_FREE(dir->fname);
02909 SAFE_FREE(dir);
02910 }
02911 return NULL;
02912 }
02913
02914 if (cli_list(targetcli, targetpath,
02915 aDIR | aSYSTEM | aHIDDEN,
02916 dir_list_fn, (void *)dir) < 0) {
02917
02918 if (dir) {
02919 SAFE_FREE(dir->fname);
02920 SAFE_FREE(dir);
02921 }
02922 saved_errno = smbc_errno(context, targetcli);
02923
02924 if (saved_errno == EINVAL) {
02925
02926
02927
02928
02929
02930
02931 *p = '\0';
02932
02933 if (smbc_getatr(context, srv, path,
02934 &mode, NULL,
02935 NULL, NULL, NULL, NULL,
02936 NULL) &&
02937 ! IS_DOS_DIR(mode)) {
02938
02939
02940 saved_errno = ENOTDIR;
02941 }
02942 }
02943
02944
02945
02946
02947
02948 cb = &context->callbacks;
02949 if (cli_is_error(targetcli) &&
02950 (cb->check_server_fn)(context, srv)) {
02951
02952
02953 if ((cb->remove_unused_server_fn)(context,
02954 srv)) {
02955
02956
02957
02958
02959
02960
02961
02962
02963 (cb->remove_cached_srv_fn)(context,
02964 srv);
02965 }
02966 }
02967
02968 errno = saved_errno;
02969 return NULL;
02970 }
02971 }
02972
02973 }
02974
02975 DLIST_ADD(context->internal->_files, dir);
02976 return dir;
02977
02978 }
02979
02980
02981
02982
02983
02984 static int
02985 smbc_closedir_ctx(SMBCCTX *context,
02986 SMBCFILE *dir)
02987 {
02988
02989 if (!context || !context->internal ||
02990 !context->internal->_initialized) {
02991
02992 errno = EINVAL;
02993 return -1;
02994
02995 }
02996
02997 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
02998
02999 errno = EBADF;
03000 return -1;
03001
03002 }
03003
03004 smbc_remove_dir(dir);
03005
03006 DLIST_REMOVE(context->internal->_files, dir);
03007
03008 if (dir) {
03009
03010 SAFE_FREE(dir->fname);
03011 SAFE_FREE(dir);
03012 }
03013
03014 return 0;
03015
03016 }
03017
03018 static void
03019 smbc_readdir_internal(SMBCCTX * context,
03020 struct smbc_dirent *dest,
03021 struct smbc_dirent *src,
03022 int max_namebuf_len)
03023 {
03024 if (context->options.urlencode_readdir_entries) {
03025
03026
03027 max_namebuf_len =
03028 smbc_urlencode(dest->name, src->name, max_namebuf_len);
03029
03030
03031 dest->namelen = strlen(dest->name);
03032
03033
03034 dest->comment = dest->name + dest->namelen + 1;
03035
03036
03037 strncpy(dest->comment, src->comment, max_namebuf_len - 1);
03038 dest->comment[max_namebuf_len - 1] = '\0';
03039
03040
03041 dest->smbc_type = src->smbc_type;
03042 dest->commentlen = strlen(dest->comment);
03043 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
03044 (char *) dest);
03045 } else {
03046
03047
03048 memcpy(dest, src, src->dirlen);
03049 dest->comment = (char *)(&dest->name + src->namelen + 1);
03050 }
03051
03052 }
03053
03054
03055
03056
03057
03058 struct smbc_dirent *
03059 smbc_readdir_ctx(SMBCCTX *context,
03060 SMBCFILE *dir)
03061 {
03062 int maxlen;
03063 struct smbc_dirent *dirp, *dirent;
03064
03065
03066
03067 if (!context || !context->internal ||
03068 !context->internal->_initialized) {
03069
03070 errno = EINVAL;
03071 DEBUG(0, ("Invalid context in smbc_readdir_ctx()\n"));
03072 return NULL;
03073
03074 }
03075
03076 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
03077
03078 errno = EBADF;
03079 DEBUG(0, ("Invalid dir in smbc_readdir_ctx()\n"));
03080 return NULL;
03081
03082 }
03083
03084 if (dir->file != False) {
03085
03086 errno = ENOTDIR;
03087 DEBUG(0, ("Found file vs directory in smbc_readdir_ctx()\n"));
03088 return NULL;
03089
03090 }
03091
03092 if (!dir->dir_next) {
03093 return NULL;
03094 }
03095
03096 dirent = dir->dir_next->dirent;
03097 if (!dirent) {
03098
03099 errno = ENOENT;
03100 return NULL;
03101
03102 }
03103
03104 dirp = (struct smbc_dirent *)context->internal->_dirent;
03105 maxlen = (sizeof(context->internal->_dirent) -
03106 sizeof(struct smbc_dirent));
03107
03108 smbc_readdir_internal(context, dirp, dirent, maxlen);
03109
03110 dir->dir_next = dir->dir_next->next;
03111
03112 return dirp;
03113 }
03114
03115
03116
03117
03118
03119 static int
03120 smbc_getdents_ctx(SMBCCTX *context,
03121 SMBCFILE *dir,
03122 struct smbc_dirent *dirp,
03123 int count)
03124 {
03125 int rem = count;
03126 int reqd;
03127 int maxlen;
03128 char *ndir = (char *)dirp;
03129 struct smbc_dir_list *dirlist;
03130
03131
03132
03133 if (!context || !context->internal ||
03134 !context->internal->_initialized) {
03135
03136 errno = EINVAL;
03137 return -1;
03138
03139 }
03140
03141 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
03142
03143 errno = EBADF;
03144 return -1;
03145
03146 }
03147
03148 if (dir->file != False) {
03149
03150 errno = ENOTDIR;
03151 return -1;
03152
03153 }
03154
03155
03156
03157
03158
03159
03160
03161 while ((dirlist = dir->dir_next)) {
03162 struct smbc_dirent *dirent;
03163
03164 if (!dirlist->dirent) {
03165
03166 errno = ENOENT;
03167 return -1;
03168
03169 }
03170
03171
03172 dirent = (struct smbc_dirent *)context->internal->_dirent;
03173 maxlen = (sizeof(context->internal->_dirent) -
03174 sizeof(struct smbc_dirent));
03175 smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen);
03176
03177 reqd = dirent->dirlen;
03178
03179 if (rem < reqd) {
03180
03181 if (rem < count) {
03182
03183 errno = 0;
03184 return count - rem;
03185
03186 }
03187 else {
03188
03189 errno = EINVAL;
03190 return -1;
03191
03192 }
03193
03194 }
03195
03196 memcpy(ndir, dirent, reqd);
03197
03198 ((struct smbc_dirent *)ndir)->comment =
03199 (char *)(&((struct smbc_dirent *)ndir)->name +
03200 dirent->namelen +
03201 1);
03202
03203 ndir += reqd;
03204
03205 rem -= reqd;
03206
03207 dir->dir_next = dirlist = dirlist -> next;
03208 }
03209
03210 if (rem == count)
03211 return 0;
03212 else
03213 return count - rem;
03214
03215 }
03216
03217
03218
03219
03220
03221 static int
03222 smbc_mkdir_ctx(SMBCCTX *context,
03223 const char *fname,
03224 mode_t mode)
03225 {
03226 SMBCSRV *srv;
03227 fstring server;
03228 fstring share;
03229 fstring user;
03230 fstring password;
03231 fstring workgroup;
03232 pstring path, targetpath;
03233 struct cli_state *targetcli;
03234
03235 if (!context || !context->internal ||
03236 !context->internal->_initialized) {
03237
03238 errno = EINVAL;
03239 return -1;
03240
03241 }
03242
03243 if (!fname) {
03244
03245 errno = EINVAL;
03246 return -1;
03247
03248 }
03249
03250 DEBUG(4, ("smbc_mkdir(%s)\n", fname));
03251
03252 if (smbc_parse_path(context, fname,
03253 workgroup, sizeof(workgroup),
03254 server, sizeof(server),
03255 share, sizeof(share),
03256 path, sizeof(path),
03257 user, sizeof(user),
03258 password, sizeof(password),
03259 NULL, 0)) {
03260 errno = EINVAL;
03261 return -1;
03262 }
03263
03264 if (user[0] == (char)0) fstrcpy(user, context->user);
03265
03266 srv = smbc_server(context, True,
03267 server, share, workgroup, user, password);
03268
03269 if (!srv) {
03270
03271 return -1;
03272
03273 }
03274
03275
03276 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
03277 {
03278 d_printf("Could not resolve %s\n", path);
03279 return -1;
03280 }
03281
03282
03283 if (!cli_mkdir(targetcli, targetpath)) {
03284
03285 errno = smbc_errno(context, targetcli);
03286 return -1;
03287
03288 }
03289
03290 return 0;
03291
03292 }
03293
03294
03295
03296
03297
03298 static int smbc_rmdir_dirempty = True;
03299
03300 static void
03301 rmdir_list_fn(const char *mnt,
03302 file_info *finfo,
03303 const char *mask,
03304 void *state)
03305 {
03306 if (strncmp(finfo->name, ".", 1) != 0 &&
03307 strncmp(finfo->name, "..", 2) != 0) {
03308
03309 smbc_rmdir_dirempty = False;
03310 }
03311 }
03312
03313
03314
03315
03316
03317 static int
03318 smbc_rmdir_ctx(SMBCCTX *context,
03319 const char *fname)
03320 {
03321 SMBCSRV *srv;
03322 fstring server;
03323 fstring share;
03324 fstring user;
03325 fstring password;
03326 fstring workgroup;
03327 pstring path;
03328 pstring targetpath;
03329 struct cli_state *targetcli;
03330
03331 if (!context || !context->internal ||
03332 !context->internal->_initialized) {
03333
03334 errno = EINVAL;
03335 return -1;
03336
03337 }
03338
03339 if (!fname) {
03340
03341 errno = EINVAL;
03342 return -1;
03343
03344 }
03345
03346 DEBUG(4, ("smbc_rmdir(%s)\n", fname));
03347
03348 if (smbc_parse_path(context, fname,
03349 workgroup, sizeof(workgroup),
03350 server, sizeof(server),
03351 share, sizeof(share),
03352 path, sizeof(path),
03353 user, sizeof(user),
03354 password, sizeof(password),
03355 NULL, 0))
03356 {
03357 errno = EINVAL;
03358 return -1;
03359 }
03360
03361 if (user[0] == (char)0) fstrcpy(user, context->user);
03362
03363 srv = smbc_server(context, True,
03364 server, share, workgroup, user, password);
03365
03366 if (!srv) {
03367
03368 return -1;
03369
03370 }
03371
03372
03373 if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath))
03374 {
03375 d_printf("Could not resolve %s\n", path);
03376 return -1;
03377 }
03378
03379
03380
03381 if (!cli_rmdir(targetcli, targetpath)) {
03382
03383 errno = smbc_errno(context, targetcli);
03384
03385 if (errno == EACCES) {
03386
03387
03388 pstring lpath;
03389
03390 smbc_rmdir_dirempty = True;
03391
03392 pstrcpy(lpath, targetpath);
03393 pstrcat(lpath, "\\*");
03394
03395 if (cli_list(targetcli, lpath,
03396 aDIR | aSYSTEM | aHIDDEN,
03397 rmdir_list_fn, NULL) < 0) {
03398
03399
03400 DEBUG(5, ("smbc_rmdir: "
03401 "cli_list returned an error: %d\n",
03402 smbc_errno(context, targetcli)));
03403 errno = EACCES;
03404
03405 }
03406
03407 if (smbc_rmdir_dirempty)
03408 errno = EACCES;
03409 else
03410 errno = ENOTEMPTY;
03411
03412 }
03413
03414 return -1;
03415
03416 }
03417
03418 return 0;
03419
03420 }
03421
03422
03423
03424
03425
03426 static off_t
03427 smbc_telldir_ctx(SMBCCTX *context,
03428 SMBCFILE *dir)
03429 {
03430 if (!context || !context->internal ||
03431 !context->internal->_initialized) {
03432
03433 errno = EINVAL;
03434 return -1;
03435
03436 }
03437
03438 if (!dir || !DLIST_CONTAINS(context->internal->_files, dir)) {
03439
03440 errno = EBADF;
03441 return -1;
03442
03443 }
03444
03445 if (dir->file != False) {
03446
03447 errno = ENOTDIR;
03448 return -1;
03449
03450 }
03451
03452
03453 if (dir->dir_next == NULL) {
03454
03455 return -1;
03456 }
03457
03458
03459
03460
03461 return (off_t)(long)dir->dir_next->dirent;
03462 }
03463
03464
03465
03466
03467
03468 struct smbc_dir_list *
03469 smbc_check_dir_ent(struct smbc_dir_list *list,
03470 struct smbc_dirent *dirent)
03471 {
03472
03473
03474
03475 if (dirent) {
03476
03477 struct smbc_dir_list *tmp = list;
03478
03479 while (tmp) {
03480
03481 if (tmp->dirent == dirent)
03482 return tmp;
03483
03484 tmp = tmp->next;
03485
03486 }
03487
03488 }
03489
03490 return NULL;
03491
03492 }
03493
03494
03495
03496
03497
03498
03499 static int
03500 smbc_lseekdir_ctx(SMBCCTX *context,
03501 SMBCFILE *dir,
03502 off_t offset)
03503 {
03504 long int l_offset = offset;
03505 struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
03506 struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
03507
03508 if (!context || !context->internal ||
03509 !context->internal->_initialized) {
03510
03511 errno = EINVAL;
03512 return -1;
03513
03514 }
03515
03516 if (dir->file != False) {
03517
03518 errno = ENOTDIR;
03519 return -1;
03520
03521 }
03522
03523
03524
03525 if (dirent == NULL) {
03526
03527 dir->dir_next = dir->dir_list;
03528 return 0;
03529
03530 }
03531
03532 if (offset == -1) {
03533 dir->dir_next = NULL;
03534 return 0;
03535 }
03536
03537
03538
03539
03540 if ((list_ent = smbc_check_dir_ent(dir->dir_list, dirent)) == NULL) {
03541
03542 errno = EINVAL;
03543 return -1;
03544
03545 }
03546
03547 dir->dir_next = list_ent;
03548
03549 return 0;
03550
03551 }
03552
03553
03554
03555
03556
03557 static int
03558 smbc_fstatdir_ctx(SMBCCTX *context,
03559 SMBCFILE *dir,
03560 struct stat *st)
03561 {
03562
03563 if (!context || !context->internal ||
03564 !context->internal->_initialized) {
03565
03566 errno = EINVAL;
03567 return -1;
03568
03569 }
03570
03571
03572
03573 return 0;
03574
03575 }
03576
03577 static int
03578 smbc_chmod_ctx(SMBCCTX *context,
03579 const char *fname,
03580 mode_t newmode)
03581 {
03582 SMBCSRV *srv;
03583 fstring server;
03584 fstring share;
03585 fstring user;
03586 fstring password;
03587 fstring workgroup;
03588 pstring path;
03589 uint16 mode;
03590
03591 if (!context || !context->internal ||
03592 !context->internal->_initialized) {
03593
03594 errno = EINVAL;
03595 return -1;
03596
03597 }
03598
03599 if (!fname) {
03600
03601 errno = EINVAL;
03602 return -1;
03603
03604 }
03605
03606 DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
03607
03608 if (smbc_parse_path(context, fname,
03609 workgroup, sizeof(workgroup),
03610 server, sizeof(server),
03611 share, sizeof(share),
03612 path, sizeof(path),
03613 user, sizeof(user),
03614 password, sizeof(password),
03615 NULL, 0)) {
03616 errno = EINVAL;
03617 return -1;
03618 }
03619
03620 if (user[0] == (char)0) fstrcpy(user, context->user);
03621
03622 srv = smbc_server(context, True,
03623 server, share, workgroup, user, password);
03624
03625 if (!srv) {
03626 return -1;
03627 }
03628
03629 mode = 0;
03630
03631 if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
03632 if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
03633 if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
03634 if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
03635
03636 if (!cli_setatr(srv->cli, path, mode, 0)) {
03637 errno = smbc_errno(context, srv->cli);
03638 return -1;
03639 }
03640
03641 return 0;
03642 }
03643
03644 static int
03645 smbc_utimes_ctx(SMBCCTX *context,
03646 const char *fname,
03647 struct timeval *tbuf)
03648 {
03649 SMBCSRV *srv;
03650 fstring server;
03651 fstring share;
03652 fstring user;
03653 fstring password;
03654 fstring workgroup;
03655 pstring path;
03656 time_t access_time;
03657 time_t write_time;
03658
03659 if (!context || !context->internal ||
03660 !context->internal->_initialized) {
03661
03662 errno = EINVAL;
03663 return -1;
03664
03665 }
03666
03667 if (!fname) {
03668
03669 errno = EINVAL;
03670 return -1;
03671
03672 }
03673
03674 if (tbuf == NULL) {
03675 access_time = write_time = time(NULL);
03676 } else {
03677 access_time = tbuf[0].tv_sec;
03678 write_time = tbuf[1].tv_sec;
03679 }
03680
03681 if (DEBUGLVL(4))
03682 {
03683 char *p;
03684 char atimebuf[32];
03685 char mtimebuf[32];
03686
03687 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
03688 atimebuf[sizeof(atimebuf) - 1] = '\0';
03689 if ((p = strchr(atimebuf, '\n')) != NULL) {
03690 *p = '\0';
03691 }
03692
03693 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
03694 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
03695 if ((p = strchr(mtimebuf, '\n')) != NULL) {
03696 *p = '\0';
03697 }
03698
03699 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
03700 fname, atimebuf, mtimebuf);
03701 }
03702
03703 if (smbc_parse_path(context, fname,
03704 workgroup, sizeof(workgroup),
03705 server, sizeof(server),
03706 share, sizeof(share),
03707 path, sizeof(path),
03708 user, sizeof(user),
03709 password, sizeof(password),
03710 NULL, 0)) {
03711 errno = EINVAL;
03712 return -1;
03713 }
03714
03715 if (user[0] == (char)0) fstrcpy(user, context->user);
03716
03717 srv = smbc_server(context, True,
03718 server, share, workgroup, user, password);
03719
03720 if (!srv) {
03721 return -1;
03722 }
03723
03724 if (!smbc_setatr(context, srv, path,
03725 0, access_time, write_time, 0, 0)) {
03726 return -1;
03727 }
03728
03729 return 0;
03730 }
03731
03732
03733
03734
03735
03736
03737
03738
03739 static int
03740 ace_compare(SEC_ACE *ace1,
03741 SEC_ACE *ace2)
03742 {
03743 BOOL b1;
03744 BOOL b2;
03745
03746
03747 if (sec_ace_equal(ace1, ace2)) {
03748 return 0;
03749 }
03750
03751
03752 b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
03753 b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0);
03754 if (b1 != b2) {
03755 return (b1 ? 1 : -1);
03756 }
03757
03758
03759
03760
03761
03762 b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
03763 ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
03764 ace1->type != SEC_ACE_TYPE_ACCESS_DENIED &&
03765 ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
03766 b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED &&
03767 ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT &&
03768 ace2->type != SEC_ACE_TYPE_ACCESS_DENIED &&
03769 ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
03770 if (b1 != b2) {
03771 return (b1 ? 1 : -1);
03772 }
03773
03774
03775 b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
03776 ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
03777 b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED ||
03778 ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT);
03779 if (b1 != b2) {
03780 return (b1 ? 1 : -1);
03781 }
03782
03783
03784
03785
03786
03787 b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
03788 ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
03789 b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ||
03790 ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT);
03791 if (b1 != b2) {
03792 return (b1 ? 1 : -1);
03793 }
03794
03795
03796
03797
03798
03799
03800
03801
03802 if (ace1->type != ace2->type) {
03803 return ace2->type - ace1->type;
03804 }
03805
03806 if (sid_compare(&ace1->trustee, &ace2->trustee)) {
03807 return sid_compare(&ace1->trustee, &ace2->trustee);
03808 }
03809
03810 if (ace1->flags != ace2->flags) {
03811 return ace1->flags - ace2->flags;
03812 }
03813
03814 if (ace1->access_mask != ace2->access_mask) {
03815 return ace1->access_mask - ace2->access_mask;
03816 }
03817
03818 if (ace1->size != ace2->size) {
03819 return ace1->size - ace2->size;
03820 }
03821
03822 return memcmp(ace1, ace2, sizeof(SEC_ACE));
03823 }
03824
03825
03826 static void
03827 sort_acl(SEC_ACL *the_acl)
03828 {
03829 uint32 i;
03830 if (!the_acl) return;
03831
03832 qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]),
03833 QSORT_CAST ace_compare);
03834
03835 for (i=1;i<the_acl->num_aces;) {
03836 if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
03837 int j;
03838 for (j=i; j<the_acl->num_aces-1; j++) {
03839 the_acl->aces[j] = the_acl->aces[j+1];
03840 }
03841 the_acl->num_aces--;
03842 } else {
03843 i++;
03844 }
03845 }
03846 }
03847
03848
03849 static void
03850 convert_sid_to_string(struct cli_state *ipc_cli,
03851 POLICY_HND *pol,
03852 fstring str,
03853 BOOL numeric,
03854 DOM_SID *sid)
03855 {
03856 char **domains = NULL;
03857 char **names = NULL;
03858 enum lsa_SidType *types = NULL;
03859 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
03860 sid_to_string(str, sid);
03861
03862 if (numeric) {
03863 return;
03864 }
03865
03866 if (!pipe_hnd) {
03867 return;
03868 }
03869
03870
03871
03872 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx,
03873 pol, 1, sid, &domains,
03874 &names, &types)) ||
03875 !domains || !domains[0] || !names || !names[0]) {
03876 return;
03877 }
03878
03879
03880
03881 slprintf(str, sizeof(fstring) - 1, "%s%s%s",
03882 domains[0], lp_winbind_separator(),
03883 names[0]);
03884 }
03885
03886
03887 static BOOL
03888 convert_string_to_sid(struct cli_state *ipc_cli,
03889 POLICY_HND *pol,
03890 BOOL numeric,
03891 DOM_SID *sid,
03892 const char *str)
03893 {
03894 enum lsa_SidType *types = NULL;
03895 DOM_SID *sids = NULL;
03896 BOOL result = True;
03897 struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
03898
03899 if (!pipe_hnd) {
03900 return False;
03901 }
03902
03903 if (numeric) {
03904 if (strncmp(str, "S-", 2) == 0) {
03905 return string_to_sid(sid, str);
03906 }
03907
03908 result = False;
03909 goto done;
03910 }
03911
03912 if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx,
03913 pol, 1, &str, NULL, &sids,
03914 &types))) {
03915 result = False;
03916 goto done;
03917 }
03918
03919 sid_copy(sid, &sids[0]);
03920 done:
03921
03922 return result;
03923 }
03924
03925
03926
03927 static BOOL
03928 parse_ace(struct cli_state *ipc_cli,
03929 POLICY_HND *pol,
03930 SEC_ACE *ace,
03931 BOOL numeric,
03932 char *str)
03933 {
03934 char *p;
03935 const char *cp;
03936 fstring tok;
03937 unsigned int atype;
03938 unsigned int aflags;
03939 unsigned int amask;
03940 DOM_SID sid;
03941 SEC_ACCESS mask;
03942 const struct perm_value *v;
03943 struct perm_value {
03944 const char *perm;
03945 uint32 mask;
03946 };
03947
03948
03949 static const struct perm_value special_values[] = {
03950 { "R", 0x00120089 },
03951 { "W", 0x00120116 },
03952 { "X", 0x001200a0 },
03953 { "D", 0x00010000 },
03954 { "P", 0x00040000 },
03955 { "O", 0x00080000 },
03956 { NULL, 0 },
03957 };
03958
03959 static const struct perm_value standard_values[] = {
03960 { "READ", 0x001200a9 },
03961 { "CHANGE", 0x001301bf },
03962 { "FULL", 0x001f01ff },
03963 { NULL, 0 },
03964 };
03965
03966
03967 ZERO_STRUCTP(ace);
03968 p = strchr_m(str,':');
03969 if (!p) return False;
03970 *p = '\0';
03971 p++;
03972
03973
03974 if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
03975 convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
03976 goto done;
03977 }
03978
03979
03980
03981 if (!convert_string_to_sid(ipc_cli, pol, numeric, &sid, str)) {
03982 return False;
03983 }
03984
03985 cp = p;
03986 if (!next_token(&cp, tok, "/", sizeof(fstring))) {
03987 return False;
03988 }
03989
03990 if (StrnCaseCmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
03991 atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
03992 } else if (StrnCaseCmp(tok, "DENIED", strlen("DENIED")) == 0) {
03993 atype = SEC_ACE_TYPE_ACCESS_DENIED;
03994 } else {
03995 return False;
03996 }
03997
03998
03999
04000 if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
04001 sscanf(tok, "%i", &aflags))) {
04002 return False;
04003 }
04004
04005 if (!next_token(&cp, tok, "/", sizeof(fstring))) {
04006 return False;
04007 }
04008
04009 if (strncmp(tok, "0x", 2) == 0) {
04010 if (sscanf(tok, "%i", &amask) != 1) {
04011 return False;
04012 }
04013 goto done;
04014 }
04015
04016 for (v = standard_values; v->perm; v++) {
04017 if (strcmp(tok, v->perm) == 0) {
04018 amask = v->mask;
04019 goto done;
04020 }
04021 }
04022
04023 p = tok;
04024
04025 while(*p) {
04026 BOOL found = False;
04027
04028 for (v = special_values; v->perm; v++) {
04029 if (v->perm[0] == *p) {
04030 amask |= v->mask;
04031 found = True;
04032 }
04033 }
04034
04035 if (!found) return False;
04036 p++;
04037 }
04038
04039 if (*p) {
04040 return False;
04041 }
04042
04043 done:
04044 mask = amask;
04045 init_sec_ace(ace, &sid, atype, mask, aflags);
04046 return True;
04047 }
04048
04049
04050 static BOOL
04051 add_ace(SEC_ACL **the_acl,
04052 SEC_ACE *ace,
04053 TALLOC_CTX *ctx)
04054 {
04055 SEC_ACL *newacl;
04056 SEC_ACE *aces;
04057
04058 if (! *the_acl) {
04059 (*the_acl) = make_sec_acl(ctx, 3, 1, ace);
04060 return True;
04061 }
04062
04063 if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) {
04064 return False;
04065 }
04066 memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
04067 memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
04068 newacl = make_sec_acl(ctx, (*the_acl)->revision,
04069 1+(*the_acl)->num_aces, aces);
04070 SAFE_FREE(aces);
04071 (*the_acl) = newacl;
04072 return True;
04073 }
04074
04075
04076
04077 static SEC_DESC *
04078 sec_desc_parse(TALLOC_CTX *ctx,
04079 struct cli_state *ipc_cli,
04080 POLICY_HND *pol,
04081 BOOL numeric,
04082 char *str)
04083 {
04084 const char *p = str;
04085 fstring tok;
04086 SEC_DESC *ret = NULL;
04087 size_t sd_size;
04088 DOM_SID *group_sid=NULL;
04089 DOM_SID *owner_sid=NULL;
04090 SEC_ACL *dacl=NULL;
04091 int revision=1;
04092
04093 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
04094
04095 if (StrnCaseCmp(tok,"REVISION:", 9) == 0) {
04096 revision = strtol(tok+9, NULL, 16);
04097 continue;
04098 }
04099
04100 if (StrnCaseCmp(tok,"OWNER:", 6) == 0) {
04101 if (owner_sid) {
04102 DEBUG(5, ("OWNER specified more than once!\n"));
04103 goto done;
04104 }
04105 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
04106 if (!owner_sid ||
04107 !convert_string_to_sid(ipc_cli, pol,
04108 numeric,
04109 owner_sid, tok+6)) {
04110 DEBUG(5, ("Failed to parse owner sid\n"));
04111 goto done;
04112 }
04113 continue;
04114 }
04115
04116 if (StrnCaseCmp(tok,"OWNER+:", 7) == 0) {
04117 if (owner_sid) {
04118 DEBUG(5, ("OWNER specified more than once!\n"));
04119 goto done;
04120 }
04121 owner_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
04122 if (!owner_sid ||
04123 !convert_string_to_sid(ipc_cli, pol,
04124 False,
04125 owner_sid, tok+7)) {
04126 DEBUG(5, ("Failed to parse owner sid\n"));
04127 goto done;
04128 }
04129 continue;
04130 }
04131
04132 if (StrnCaseCmp(tok,"GROUP:", 6) == 0) {
04133 if (group_sid) {
04134 DEBUG(5, ("GROUP specified more than once!\n"));
04135 goto done;
04136 }
04137 group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
04138 if (!group_sid ||
04139 !convert_string_to_sid(ipc_cli, pol,
04140 numeric,
04141 group_sid, tok+6)) {
04142 DEBUG(5, ("Failed to parse group sid\n"));
04143 goto done;
04144 }
04145 continue;
04146 }
04147
04148 if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) {
04149 if (group_sid) {
04150 DEBUG(5, ("GROUP specified more than once!\n"));
04151 goto done;
04152 }
04153 group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1);
04154 if (!group_sid ||
04155 !convert_string_to_sid(ipc_cli, pol,
04156 False,
04157 group_sid, tok+6)) {
04158 DEBUG(5, ("Failed to parse group sid\n"));
04159 goto done;
04160 }
04161 continue;
04162 }
04163
04164 if (StrnCaseCmp(tok,"ACL:", 4) == 0) {
04165 SEC_ACE ace;
04166 if (!parse_ace(ipc_cli, pol, &ace, numeric, tok+4)) {
04167 DEBUG(5, ("Failed to parse ACL %s\n", tok));
04168 goto done;
04169 }
04170 if(!add_ace(&dacl, &ace, ctx)) {
04171 DEBUG(5, ("Failed to add ACL %s\n", tok));
04172 goto done;
04173 }
04174 continue;
04175 }
04176
04177 if (StrnCaseCmp(tok,"ACL+:", 5) == 0) {
04178 SEC_ACE ace;
04179 if (!parse_ace(ipc_cli, pol, &ace, False, tok+5)) {
04180 DEBUG(5, ("Failed to parse ACL %s\n", tok));
04181 goto done;
04182 }
04183 if(!add_ace(&dacl, &ace, ctx)) {
04184 DEBUG(5, ("Failed to add ACL %s\n", tok));
04185 goto done;
04186 }
04187 continue;
04188 }
04189
04190 DEBUG(5, ("Failed to parse security descriptor\n"));
04191 goto done;
04192 }
04193
04194 ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE,
04195 owner_sid, group_sid, NULL, dacl, &sd_size);
04196
04197 done:
04198 SAFE_FREE(group_sid);
04199 SAFE_FREE(owner_sid);
04200
04201 return ret;
04202 }
04203
04204
04205
04206 static DOS_ATTR_DESC *
04207 dos_attr_query(SMBCCTX *context,
04208 TALLOC_CTX *ctx,
04209 const char *filename,
04210 SMBCSRV *srv)
04211 {
04212 struct timespec create_time_ts;
04213 struct timespec write_time_ts;
04214 struct timespec access_time_ts;
04215 struct timespec change_time_ts;
04216 SMB_OFF_T size = 0;
04217 uint16 mode = 0;
04218 SMB_INO_T inode = 0;
04219 DOS_ATTR_DESC *ret;
04220
04221 ret = TALLOC_P(ctx, DOS_ATTR_DESC);
04222 if (!ret) {
04223 errno = ENOMEM;
04224 return NULL;
04225 }
04226
04227
04228 if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename),
04229 &mode, &size,
04230 &create_time_ts,
04231 &access_time_ts,
04232 &write_time_ts,
04233 &change_time_ts,
04234 &inode)) {
04235
04236 errno = smbc_errno(context, srv->cli);
04237 DEBUG(5, ("dos_attr_query Failed to query old attributes\n"));
04238 return NULL;
04239
04240 }
04241
04242 ret->mode = mode;
04243 ret->size = size;
04244 ret->create_time = convert_timespec_to_time_t(create_time_ts);
04245 ret->access_time = convert_timespec_to_time_t(access_time_ts);
04246 ret->write_time = convert_timespec_to_time_t(write_time_ts);
04247 ret->change_time = convert_timespec_to_time_t(change_time_ts);
04248 ret->inode = inode;
04249
04250 return ret;
04251 }
04252
04253
04254
04255 static void
04256 dos_attr_parse(SMBCCTX *context,
04257 DOS_ATTR_DESC *dad,
04258 SMBCSRV *srv,
04259 char *str)
04260 {
04261 int n;
04262 const char *p = str;
04263 fstring tok;
04264 struct {
04265 const char * create_time_attr;
04266 const char * access_time_attr;
04267 const char * write_time_attr;
04268 const char * change_time_attr;
04269 } attr_strings;
04270
04271
04272 if (context->internal->_full_time_names) {
04273
04274 attr_strings.create_time_attr = "CREATE_TIME";
04275 attr_strings.access_time_attr = "ACCESS_TIME";
04276 attr_strings.write_time_attr = "WRITE_TIME";
04277 attr_strings.change_time_attr = "CHANGE_TIME";
04278 } else {
04279
04280 attr_strings.create_time_attr = NULL;
04281 attr_strings.access_time_attr = "A_TIME";
04282 attr_strings.write_time_attr = "M_TIME";
04283 attr_strings.change_time_attr = "C_TIME";
04284 }
04285
04286
04287 if (*str == '*') {
04288
04289 if ((p = strchr(str, ':')) != NULL) {
04290 ++p;
04291 } else {
04292 p = str;
04293 }
04294 }
04295
04296 while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
04297
04298 if (StrnCaseCmp(tok, "MODE:", 5) == 0) {
04299 dad->mode = strtol(tok+5, NULL, 16);
04300 continue;
04301 }
04302
04303 if (StrnCaseCmp(tok, "SIZE:", 5) == 0) {
04304 dad->size = (SMB_OFF_T)atof(tok+5);
04305 continue;
04306 }
04307
04308 n = strlen(attr_strings.access_time_attr);
04309 if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) {
04310 dad->access_time = (time_t)strtol(tok+n+1, NULL, 10);
04311 continue;
04312 }
04313
04314 n = strlen(attr_strings.change_time_attr);
04315 if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) {
04316 dad->change_time = (time_t)strtol(tok+n+1, NULL, 10);
04317 continue;
04318 }
04319
04320 n = strlen(attr_strings.write_time_attr);
04321 if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) {
04322 dad->write_time = (time_t)strtol(tok+n+1, NULL, 10);
04323 continue;
04324 }
04325
04326 if (attr_strings.create_time_attr != NULL) {
04327 n = strlen(attr_strings.create_time_attr);
04328 if (StrnCaseCmp(tok, attr_strings.create_time_attr,
04329 n) == 0) {
04330 dad->create_time = (time_t)strtol(tok+n+1,
04331 NULL, 10);
04332 continue;
04333 }
04334 }
04335
04336 if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
04337 dad->inode = (SMB_INO_T)atof(tok+6);
04338 continue;
04339 }
04340 }
04341 }
04342
04343
04344
04345
04346
04347 static int
04348 cacl_get(SMBCCTX *context,
04349 TALLOC_CTX *ctx,
04350 SMBCSRV *srv,
04351 struct cli_state *ipc_cli,
04352 POLICY_HND *pol,
04353 char *filename,
04354 char *attr_name,
04355 char *buf,
04356 int bufsize)
04357 {
04358 uint32 i;
04359 int n = 0;
04360 int n_used;
04361 BOOL all;
04362 BOOL all_nt;
04363 BOOL all_nt_acls;
04364 BOOL all_dos;
04365 BOOL some_nt;
04366 BOOL some_dos;
04367 BOOL exclude_nt_revision = False;
04368 BOOL exclude_nt_owner = False;
04369 BOOL exclude_nt_group = False;
04370 BOOL exclude_nt_acl = False;
04371 BOOL exclude_dos_mode = False;
04372 BOOL exclude_dos_size = False;
04373 BOOL exclude_dos_create_time = False;
04374 BOOL exclude_dos_access_time = False;
04375 BOOL exclude_dos_write_time = False;
04376 BOOL exclude_dos_change_time = False;
04377 BOOL exclude_dos_inode = False;
04378 BOOL numeric = True;
04379 BOOL determine_size = (bufsize == 0);
04380 int fnum = -1;
04381 SEC_DESC *sd;
04382 fstring sidstr;
04383 fstring name_sandbox;
04384 char *name;
04385 char *pExclude;
04386 char *p;
04387 struct timespec create_time_ts;
04388 struct timespec write_time_ts;
04389 struct timespec access_time_ts;
04390 struct timespec change_time_ts;
04391 time_t create_time = (time_t)0;
04392 time_t write_time = (time_t)0;
04393 time_t access_time = (time_t)0;
04394 time_t change_time = (time_t)0;
04395 SMB_OFF_T size = 0;
04396 uint16 mode = 0;
04397 SMB_INO_T ino = 0;
04398 struct cli_state *cli = srv->cli;
04399 struct {
04400 const char * create_time_attr;
04401 const char * access_time_attr;
04402 const char * write_time_attr;
04403 const char * change_time_attr;
04404 } attr_strings;
04405 struct {
04406 const char * create_time_attr;
04407 const char * access_time_attr;
04408 const char * write_time_attr;
04409 const char * change_time_attr;
04410 } excl_attr_strings;
04411
04412
04413 if (context->internal->_full_time_names) {
04414
04415 attr_strings.create_time_attr = "CREATE_TIME";
04416 attr_strings.access_time_attr = "ACCESS_TIME";
04417 attr_strings.write_time_attr = "WRITE_TIME";
04418 attr_strings.change_time_attr = "CHANGE_TIME";
04419
04420 excl_attr_strings.create_time_attr = "CREATE_TIME";
04421 excl_attr_strings.access_time_attr = "ACCESS_TIME";
04422 excl_attr_strings.write_time_attr = "WRITE_TIME";
04423 excl_attr_strings.change_time_attr = "CHANGE_TIME";
04424 } else {
04425
04426 attr_strings.create_time_attr = NULL;
04427 attr_strings.access_time_attr = "A_TIME";
04428 attr_strings.write_time_attr = "M_TIME";
04429 attr_strings.change_time_attr = "C_TIME";
04430
04431 excl_attr_strings.create_time_attr = NULL;
04432 excl_attr_strings.access_time_attr = "dos_attr.A_TIME";
04433 excl_attr_strings.write_time_attr = "dos_attr.M_TIME";
04434 excl_attr_strings.change_time_attr = "dos_attr.C_TIME";
04435 }
04436
04437
04438 strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1);
04439
04440
04441 name_sandbox[sizeof(name_sandbox) - 1] = '\0';
04442
04443
04444 name = name_sandbox;
04445
04446
04447 if ((pExclude = strchr(name, '!')) != NULL)
04448 {
04449 *pExclude++ = '\0';
04450 }
04451
04452 all = (StrnCaseCmp(name, "system.*", 8) == 0);
04453 all_nt = (StrnCaseCmp(name, "system.nt_sec_desc.*", 20) == 0);
04454 all_nt_acls = (StrnCaseCmp(name, "system.nt_sec_desc.acl.*", 24) == 0);
04455 all_dos = (StrnCaseCmp(name, "system.dos_attr.*", 17) == 0);
04456 some_nt = (StrnCaseCmp(name, "system.nt_sec_desc.", 19) == 0);
04457 some_dos = (StrnCaseCmp(name, "system.dos_attr.", 16) == 0);
04458 numeric = (* (name + strlen(name) - 1) != '+');
04459
04460
04461 if (all || all_nt || all_dos) {
04462
04463
04464 for (;
04465 pExclude != NULL;
04466 pExclude = (p == NULL ? NULL : p + 1)) {
04467
04468
04469 if ((p = strchr(pExclude, '!')) != NULL)
04470 {
04471 *p = '\0';
04472 }
04473
04474
04475 if (StrCaseCmp(pExclude, "nt_sec_desc.revision") == 0) {
04476 exclude_nt_revision = True;
04477 }
04478 else if (StrCaseCmp(pExclude, "nt_sec_desc.owner") == 0) {
04479 exclude_nt_owner = True;
04480 }
04481 else if (StrCaseCmp(pExclude, "nt_sec_desc.group") == 0) {
04482 exclude_nt_group = True;
04483 }
04484 else if (StrCaseCmp(pExclude, "nt_sec_desc.acl") == 0) {
04485 exclude_nt_acl = True;
04486 }
04487 else if (StrCaseCmp(pExclude, "dos_attr.mode") == 0) {
04488 exclude_dos_mode = True;
04489 }
04490 else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) {
04491 exclude_dos_size = True;
04492 }
04493 else if (excl_attr_strings.create_time_attr != NULL &&
04494 StrCaseCmp(pExclude,
04495 excl_attr_strings.change_time_attr) == 0) {
04496 exclude_dos_create_time = True;
04497 }
04498 else if (StrCaseCmp(pExclude,
04499 excl_attr_strings.access_time_attr) == 0) {
04500 exclude_dos_access_time = True;
04501 }
04502 else if (StrCaseCmp(pExclude,
04503 excl_attr_strings.write_time_attr) == 0) {
04504 exclude_dos_write_time = True;
04505 }
04506 else if (StrCaseCmp(pExclude,
04507 excl_attr_strings.change_time_attr) == 0) {
04508 exclude_dos_change_time = True;
04509 }
04510 else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) {
04511 exclude_dos_inode = True;
04512 }
04513 else {
04514 DEBUG(5, ("cacl_get received unknown exclusion: %s\n",
04515 pExclude));
04516 errno = ENOATTR;
04517 return -1;
04518 }
04519 }
04520 }
04521
04522 n_used = 0;
04523
04524
04525
04526
04527
04528 if (ipc_cli && (all || some_nt || all_nt_acls)) {
04529
04530 name += 19;
04531
04532
04533 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
04534
04535 if (fnum == -1) {
04536 DEBUG(5, ("cacl_get failed to open %s: %s\n",
04537 filename, cli_errstr(cli)));
04538 errno = 0;
04539 return -1;
04540 }
04541
04542 sd = cli_query_secdesc(cli, fnum, ctx);
04543
04544 if (!sd) {
04545 DEBUG(5,
04546 ("cacl_get Failed to query old descriptor\n"));
04547 errno = 0;
04548 return -1;
04549 }
04550
04551 cli_close(cli, fnum);
04552
04553 if (! exclude_nt_revision) {
04554 if (all || all_nt) {
04555 if (determine_size) {
04556 p = talloc_asprintf(ctx,
04557 "REVISION:%d",
04558 sd->revision);
04559 if (!p) {
04560 errno = ENOMEM;
04561 return -1;
04562 }
04563 n = strlen(p);
04564 } else {
04565 n = snprintf(buf, bufsize,
04566 "REVISION:%d",
04567 sd->revision);
04568 }
04569 } else if (StrCaseCmp(name, "revision") == 0) {
04570 if (determine_size) {
04571 p = talloc_asprintf(ctx, "%d",
04572 sd->revision);
04573 if (!p) {
04574 errno = ENOMEM;
04575 return -1;
04576 }
04577 n = strlen(p);
04578 } else {
04579 n = snprintf(buf, bufsize, "%d",
04580 sd->revision);
04581 }
04582 }
04583
04584 if (!determine_size && n > bufsize) {
04585 errno = ERANGE;
04586 return -1;
04587 }
04588 buf += n;
04589 n_used += n;
04590 bufsize -= n;
04591 n = 0;
04592 }
04593
04594 if (! exclude_nt_owner) {
04595
04596 if (sd->owner_sid) {
04597 convert_sid_to_string(ipc_cli, pol,
04598 sidstr,
04599 numeric,
04600 sd->owner_sid);
04601 } else {
04602 fstrcpy(sidstr, "");
04603 }
04604
04605 if (all || all_nt) {
04606 if (determine_size) {
04607 p = talloc_asprintf(ctx, ",OWNER:%s",
04608 sidstr);
04609 if (!p) {
04610 errno = ENOMEM;
04611 return -1;
04612 }
04613 n = strlen(p);
04614 } else if (sidstr[0] != '\0') {
04615 n = snprintf(buf, bufsize,
04616 ",OWNER:%s", sidstr);
04617 }
04618 } else if (StrnCaseCmp(name, "owner", 5) == 0) {
04619 if (determine_size) {
04620 p = talloc_asprintf(ctx, "%s", sidstr);
04621 if (!p) {
04622 errno = ENOMEM;
04623 return -1;
04624 }
04625 n = strlen(p);
04626 } else {
04627 n = snprintf(buf, bufsize, "%s",
04628 sidstr);
04629 }
04630 }
04631
04632 if (!determine_size && n > bufsize) {
04633 errno = ERANGE;
04634 return -1;
04635 }
04636 buf += n;
04637 n_used += n;
04638 bufsize -= n;
04639 n = 0;
04640 }
04641
04642 if (! exclude_nt_group) {
04643 if (sd->group_sid) {
04644 convert_sid_to_string(ipc_cli, pol,
04645 sidstr, numeric,
04646 sd->group_sid);
04647 } else {
04648 fstrcpy(sidstr, "");
04649 }
04650
04651 if (all || all_nt) {
04652 if (determine_size) {
04653 p = talloc_asprintf(ctx, ",GROUP:%s",
04654 sidstr);
04655 if (!p) {
04656 errno = ENOMEM;
04657 return -1;
04658 }
04659 n = strlen(p);
04660 } else if (sidstr[0] != '\0') {
04661 n = snprintf(buf, bufsize,
04662 ",GROUP:%s", sidstr);
04663 }
04664 } else if (StrnCaseCmp(name, "group", 5) == 0) {
04665 if (determine_size) {
04666 p = talloc_asprintf(ctx, "%s", sidstr);
04667 if (!p) {
04668 errno = ENOMEM;
04669 return -1;
04670 }
04671 n = strlen(p);
04672 } else {
04673 n = snprintf(buf, bufsize,
04674 "%s", sidstr);
04675 }
04676 }
04677
04678 if (!determine_size && n > bufsize) {
04679 errno = ERANGE;
04680 return -1;
04681 }
04682 buf += n;
04683 n_used += n;
04684 bufsize -= n;
04685 n = 0;
04686 }
04687
04688 if (! exclude_nt_acl) {
04689
04690 for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
04691
04692 SEC_ACE *ace = &sd->dacl->aces[i];
04693 convert_sid_to_string(ipc_cli, pol,
04694 sidstr, numeric,
04695 &ace->trustee);
04696
04697 if (all || all_nt) {
04698 if (determine_size) {
04699 p = talloc_asprintf(
04700 ctx,
04701 ",ACL:"
04702 "%s:%d/%d/0x%08x",
04703 sidstr,
04704 ace->type,
04705 ace->flags,
04706 ace->access_mask);
04707 if (!p) {
04708 errno = ENOMEM;
04709 return -1;
04710 }
04711 n = strlen(p);
04712 } else {
04713 n = snprintf(
04714 buf, bufsize,
04715 ",ACL:%s:%d/%d/0x%08x",
04716 sidstr,
04717 ace->type,
04718 ace->flags,
04719 ace->access_mask);
04720 }
04721 } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
04722 StrCaseCmp(name+3, sidstr) == 0) ||
04723 (StrnCaseCmp(name, "acl+", 4) == 0 &&
04724 StrCaseCmp(name+4, sidstr) == 0)) {
04725 if (determine_size) {
04726 p = talloc_asprintf(
04727 ctx,
04728 "%d/%d/0x%08x",
04729 ace->type,
04730 ace->flags,
04731 ace->access_mask);
04732 if (!p) {
04733 errno = ENOMEM;
04734 return -1;
04735 }
04736 n = strlen(p);
04737 } else {
04738 n = snprintf(buf, bufsize,
04739 "%d/%d/0x%08x",
04740 ace->type,
04741 ace->flags,
04742 ace->access_mask);
04743 }
04744 } else if (all_nt_acls) {
04745 if (determine_size) {
04746 p = talloc_asprintf(
04747 ctx,
04748 "%s%s:%d/%d/0x%08x",
04749 i ? "," : "",
04750 sidstr,
04751 ace->type,
04752 ace->flags,
04753 ace->access_mask);
04754 if (!p) {
04755 errno = ENOMEM;
04756 return -1;
04757 }
04758 n = strlen(p);
04759 } else {
04760 n = snprintf(buf, bufsize,
04761 "%s%s:%d/%d/0x%08x",
04762 i ? "," : "",
04763 sidstr,
04764 ace->type,
04765 ace->flags,
04766 ace->access_mask);
04767 }
04768 }
04769 if (!determine_size && n > bufsize) {
04770 errno = ERANGE;
04771 return -1;
04772 }
04773 buf += n;
04774 n_used += n;
04775 bufsize -= n;
04776 n = 0;
04777 }
04778 }
04779
04780
04781 name -= 19;
04782 }
04783
04784 if (all || some_dos) {
04785
04786 name += 16;
04787
04788
04789 if (!smbc_getatr(context, srv, filename, &mode, &size,
04790 &create_time_ts,
04791 &access_time_ts,
04792 &write_time_ts,
04793 &change_time_ts,
04794 &ino)) {
04795
04796 errno = smbc_errno(context, srv->cli);
04797 return -1;
04798
04799 }
04800
04801 create_time = convert_timespec_to_time_t(create_time_ts);
04802 access_time = convert_timespec_to_time_t(access_time_ts);
04803 write_time = convert_timespec_to_time_t(write_time_ts);
04804 change_time = convert_timespec_to_time_t(change_time_ts);
04805
04806 if (! exclude_dos_mode) {
04807 if (all || all_dos) {
04808 if (determine_size) {
04809 p = talloc_asprintf(ctx,
04810 "%sMODE:0x%x",
04811 (ipc_cli &&
04812 (all || some_nt)
04813 ? ","
04814 : ""),
04815 mode);
04816 if (!p) {
04817 errno = ENOMEM;
04818 return -1;
04819 }
04820 n = strlen(p);
04821 } else {
04822 n = snprintf(buf, bufsize,
04823 "%sMODE:0x%x",
04824 (ipc_cli &&
04825 (all || some_nt)
04826 ? ","
04827 : ""),
04828 mode);
04829 }
04830 } else if (StrCaseCmp(name, "mode") == 0) {
04831 if (determine_size) {
04832 p = talloc_asprintf(ctx, "0x%x", mode);
04833 if (!p) {
04834 errno = ENOMEM;
04835 return -1;
04836 }
04837 n = strlen(p);
04838 } else {
04839 n = snprintf(buf, bufsize,
04840 "0x%x", mode);
04841 }
04842 }
04843
04844 if (!determine_size && n > bufsize) {
04845 errno = ERANGE;
04846 return -1;
04847 }
04848 buf += n;
04849 n_used += n;
04850 bufsize -= n;
04851 n = 0;
04852 }
04853
04854 if (! exclude_dos_size) {
04855 if (all || all_dos) {
04856 if (determine_size) {
04857 p = talloc_asprintf(
04858 ctx,
04859 ",SIZE:%.0f",
04860 (double)size);
04861 if (!p) {
04862 errno = ENOMEM;
04863 return -1;
04864 }
04865 n = strlen(p);
04866 } else {
04867 n = snprintf(buf, bufsize,
04868 ",SIZE:%.0f",
04869 (double)size);
04870 }
04871 } else if (StrCaseCmp(name, "size") == 0) {
04872 if (determine_size) {
04873 p = talloc_asprintf(
04874 ctx,
04875 "%.0f",
04876 (double)size);
04877 if (!p) {
04878 errno = ENOMEM;
04879 return -1;
04880 }
04881 n = strlen(p);
04882 } else {
04883 n = snprintf(buf, bufsize,
04884 "%.0f",
04885 (double)size);
04886 }
04887 }
04888
04889 if (!determine_size && n > bufsize) {
04890 errno = ERANGE;
04891 return -1;
04892 }
04893 buf += n;
04894 n_used += n;
04895 bufsize -= n;
04896 n = 0;
04897 }
04898
04899 if (! exclude_dos_create_time &&
04900 attr_strings.create_time_attr != NULL) {
04901 if (all || all_dos) {
04902 if (determine_size) {
04903 p = talloc_asprintf(ctx,
04904 ",%s:%lu",
04905 attr_strings.create_time_attr,
04906 create_time);
04907 if (!p) {
04908 errno = ENOMEM;
04909 return -1;
04910 }
04911 n = strlen(p);
04912 } else {
04913 n = snprintf(buf, bufsize,
04914 ",%s:%lu",
04915 attr_strings.create_time_attr,
04916 create_time);
04917 }
04918 } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) {
04919 if (determine_size) {
04920 p = talloc_asprintf(ctx, "%lu", create_time);
04921 if (!p) {
04922 errno = ENOMEM;
04923 return -1;
04924 }
04925 n = strlen(p);
04926 } else {
04927 n = snprintf(buf, bufsize,
04928 "%lu", create_time);
04929 }
04930 }
04931
04932 if (!determine_size && n > bufsize) {
04933 errno = ERANGE;
04934 return -1;
04935 }
04936 buf += n;
04937 n_used += n;
04938 bufsize -= n;
04939 n = 0;
04940 }
04941
04942 if (! exclude_dos_access_time) {
04943 if (all || all_dos) {
04944 if (determine_size) {
04945 p = talloc_asprintf(ctx,
04946 ",%s:%lu",
04947 attr_strings.access_time_attr,
04948 access_time);
04949 if (!p) {
04950 errno = ENOMEM;
04951 return -1;
04952 }
04953 n = strlen(p);
04954 } else {
04955 n = snprintf(buf, bufsize,
04956 ",%s:%lu",
04957 attr_strings.access_time_attr,
04958 access_time);
04959 }
04960 } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) {
04961 if (determine_size) {
04962 p = talloc_asprintf(ctx, "%lu", access_time);
04963 if (!p) {
04964 errno = ENOMEM;
04965 return -1;
04966 }
04967 n = strlen(p);
04968 } else {
04969 n = snprintf(buf, bufsize,
04970 "%lu", access_time);
04971 }
04972 }
04973
04974 if (!determine_size && n > bufsize) {
04975 errno = ERANGE;
04976 return -1;
04977 }
04978 buf += n;
04979 n_used += n;
04980 bufsize -= n;
04981 n = 0;
04982 }
04983
04984 if (! exclude_dos_write_time) {
04985 if (all || all_dos) {
04986 if (determine_size) {
04987 p = talloc_asprintf(ctx,
04988 ",%s:%lu",
04989 attr_strings.write_time_attr,
04990 write_time);
04991 if (!p) {
04992 errno = ENOMEM;
04993 return -1;
04994 }
04995 n = strlen(p);
04996 } else {
04997 n = snprintf(buf, bufsize,
04998 ",%s:%lu",
04999 attr_strings.write_time_attr,
05000 write_time);
05001 }
05002 } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) {
05003 if (determine_size) {
05004 p = talloc_asprintf(ctx, "%lu", write_time);
05005 if (!p) {
05006 errno = ENOMEM;
05007 return -1;
05008 }
05009 n = strlen(p);
05010 } else {
05011 n = snprintf(buf, bufsize,
05012 "%lu", write_time);
05013 }
05014 }
05015
05016 if (!determine_size && n > bufsize) {
05017 errno = ERANGE;
05018 return -1;
05019 }
05020 buf += n;
05021 n_used += n;
05022 bufsize -= n;
05023 n = 0;
05024 }
05025
05026 if (! exclude_dos_change_time) {
05027 if (all || all_dos) {
05028 if (determine_size) {
05029 p = talloc_asprintf(ctx,
05030 ",%s:%lu",
05031 attr_strings.change_time_attr,
05032 change_time);
05033 if (!p) {
05034 errno = ENOMEM;
05035 return -1;
05036 }
05037 n = strlen(p);
05038 } else {
05039 n = snprintf(buf, bufsize,
05040 ",%s:%lu",
05041 attr_strings.change_time_attr,
05042 change_time);
05043 }
05044 } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
05045 if (determine_size) {
05046 p = talloc_asprintf(ctx, "%lu", change_time);
05047 if (!p) {
05048 errno = ENOMEM;
05049 return -1;
05050 }
05051 n = strlen(p);
05052 } else {
05053 n = snprintf(buf, bufsize,
05054 "%lu", change_time);
05055 }
05056 }
05057
05058 if (!determine_size && n > bufsize) {
05059 errno = ERANGE;
05060 return -1;
05061 }
05062 buf += n;
05063 n_used += n;
05064 bufsize -= n;
05065 n = 0;
05066 }
05067
05068 if (! exclude_dos_inode) {
05069 if (all || all_dos) {
05070 if (determine_size) {
05071 p = talloc_asprintf(
05072 ctx,
05073 ",INODE:%.0f",
05074 (double)ino);
05075 if (!p) {
05076 errno = ENOMEM;
05077 return -1;
05078 }
05079 n = strlen(p);
05080 } else {
05081 n = snprintf(buf, bufsize,
05082 ",INODE:%.0f",
05083 (double) ino);
05084 }
05085 } else if (StrCaseCmp(name, "inode") == 0) {
05086 if (determine_size) {
05087 p = talloc_asprintf(
05088 ctx,
05089 "%.0f",
05090 (double) ino);
05091 if (!p) {
05092 errno = ENOMEM;
05093 return -1;
05094 }
05095 n = strlen(p);
05096 } else {
05097 n = snprintf(buf, bufsize,
05098 "%.0f",
05099 (double) ino);
05100 }
05101 }
05102
05103 if (!determine_size && n > bufsize) {
05104 errno = ERANGE;
05105 return -1;
05106 }
05107 buf += n;
05108 n_used += n;
05109 bufsize -= n;
05110 n = 0;
05111 }
05112
05113
05114 name -= 16;
05115 }
05116
05117 if (n_used == 0) {
05118 errno = ENOATTR;
05119 return -1;
05120 }
05121
05122 return n_used;
05123 }
05124
05125
05126
05127
05128
05129 static int
05130 cacl_set(TALLOC_CTX *ctx,
05131 struct cli_state *cli,
05132 struct cli_state *ipc_cli,
05133 POLICY_HND *pol,
05134 const char *filename,
05135 const char *the_acl,
05136 int mode,
05137 int flags)
05138 {
05139 int fnum;
05140 int err = 0;
05141 SEC_DESC *sd = NULL, *old;
05142 SEC_ACL *dacl = NULL;
05143 DOM_SID *owner_sid = NULL;
05144 DOM_SID *group_sid = NULL;
05145 uint32 i, j;
05146 size_t sd_size;
05147 int ret = 0;
05148 char *p;
05149 BOOL numeric = True;
05150
05151
05152 if (the_acl) {
05153 numeric = ((p = strchr(the_acl, ':')) != NULL &&
05154 p > the_acl &&
05155 p[-1] != '+');
05156
05157
05158 if (*the_acl == '*') {
05159
05160 the_acl = p + 1;
05161 }
05162
05163 sd = sec_desc_parse(ctx, ipc_cli, pol, numeric,
05164 CONST_DISCARD(char *, the_acl));
05165
05166 if (!sd) {
05167 errno = EINVAL;
05168 return -1;
05169 }
05170 }
05171
05172
05173
05174
05175 if (!sd && (mode != SMBC_XATTR_MODE_REMOVE_ALL)) {
05176 errno = EINVAL;
05177 return -1;
05178 }
05179
05180
05181
05182
05183 fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
05184
05185 if (fnum == -1) {
05186 DEBUG(5, ("cacl_set failed to open %s: %s\n",
05187 filename, cli_errstr(cli)));
05188 errno = 0;
05189 return -1;
05190 }
05191
05192 old = cli_query_secdesc(cli, fnum, ctx);
05193
05194 if (!old) {
05195 DEBUG(5, ("cacl_set Failed to query old descriptor\n"));
05196 errno = 0;
05197 return -1;
05198 }
05199
05200 cli_close(cli, fnum);
05201
05202 switch (mode) {
05203 case SMBC_XATTR_MODE_REMOVE_ALL:
05204 old->dacl->num_aces = 0;
05205 dacl = old->dacl;
05206 break;
05207
05208 case SMBC_XATTR_MODE_REMOVE:
05209 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
05210 BOOL found = False;
05211
05212 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
05213 if (sec_ace_equal(&sd->dacl->aces[i],
05214 &old->dacl->aces[j])) {
05215 uint32 k;
05216 for (k=j; k<old->dacl->num_aces-1;k++) {
05217 old->dacl->aces[k] =
05218 old->dacl->aces[k+1];
05219 }
05220 old->dacl->num_aces--;
05221 found = True;
05222 dacl = old->dacl;
05223 break;
05224 }
05225 }
05226
05227 if (!found) {
05228 err = ENOATTR;
05229 ret = -1;
05230 goto failed;
05231 }
05232 }
05233 break;
05234
05235 case SMBC_XATTR_MODE_ADD:
05236 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
05237 BOOL found = False;
05238
05239 for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
05240 if (sid_equal(&sd->dacl->aces[i].trustee,
05241 &old->dacl->aces[j].trustee)) {
05242 if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
05243 err = EEXIST;
05244 ret = -1;
05245 goto failed;
05246 }
05247 old->dacl->aces[j] = sd->dacl->aces[i];
05248 ret = -1;
05249 found = True;
05250 }
05251 }
05252
05253 if (!found && (flags & SMBC_XATTR_FLAG_REPLACE)) {
05254 err = ENOATTR;
05255 ret = -1;
05256 goto failed;
05257 }
05258
05259 for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
05260 add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
05261 }
05262 }
05263 dacl = old->dacl;
05264 break;
05265
05266 case SMBC_XATTR_MODE_SET:
05267 old = sd;
05268 owner_sid = old->owner_sid;
05269 group_sid = old->group_sid;
05270 dacl = old->dacl;
05271 break;
05272
05273 case SMBC_XATTR_MODE_CHOWN:
05274 owner_sid = sd->owner_sid;
05275 break;
05276
05277 case SMBC_XATTR_MODE_CHGRP:
05278 group_sid = sd->group_sid;
05279 break;
05280 }
05281
05282
05283 sort_acl(old->dacl);
05284
05285
05286 sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE,
05287 owner_sid, group_sid, NULL, dacl, &sd_size);
05288
05289 fnum = cli_nt_create(cli, filename,
05290 WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS);
05291
05292 if (fnum == -1) {
05293 DEBUG(5, ("cacl_set failed to open %s: %s\n",
05294 filename, cli_errstr(cli)));
05295 errno = 0;
05296 return -1;
05297 }
05298
05299 if (!cli_set_secdesc(cli, fnum, sd)) {
05300 DEBUG(5, ("ERROR: secdesc set failed: %s\n", cli_errstr(cli)));
05301 ret = -1;
05302 }
05303
05304
05305
05306 failed:
05307 cli_close(cli, fnum);
05308
05309 if (err != 0) {
05310 errno = err;
05311 }
05312
05313 return ret;
05314 }
05315
05316
05317 static int
05318 smbc_setxattr_ctx(SMBCCTX *context,
05319 const char *fname,
05320 const char *name,
05321 const void *value,
05322 size_t size,
05323 int flags)
05324 {
05325 int ret;
05326 int ret2;
05327 SMBCSRV *srv;
05328 SMBCSRV *ipc_srv;
05329 fstring server;
05330 fstring share;
05331 fstring user;
05332 fstring password;
05333 fstring workgroup;
05334 pstring path;
05335 TALLOC_CTX *ctx;
05336 POLICY_HND pol;
05337 DOS_ATTR_DESC *dad;
05338 struct {
05339 const char * create_time_attr;
05340 const char * access_time_attr;
05341 const char * write_time_attr;
05342 const char * change_time_attr;
05343 } attr_strings;
05344
05345 if (!context || !context->internal ||
05346 !context->internal->_initialized) {
05347
05348 errno = EINVAL;
05349 return -1;
05350
05351 }
05352
05353 if (!fname) {
05354
05355 errno = EINVAL;
05356 return -1;
05357
05358 }
05359
05360 DEBUG(4, ("smbc_setxattr(%s, %s, %.*s)\n",
05361 fname, name, (int) size, (const char*)value));
05362
05363 if (smbc_parse_path(context, fname,
05364 workgroup, sizeof(workgroup),
05365 server, sizeof(server),
05366 share, sizeof(share),
05367 path, sizeof(path),
05368 user, sizeof(user),
05369 password, sizeof(password),
05370 NULL, 0)) {
05371 errno = EINVAL;
05372 return -1;
05373 }
05374
05375 if (user[0] == (char)0) fstrcpy(user, context->user);
05376
05377 srv = smbc_server(context, True,
05378 server, share, workgroup, user, password);
05379 if (!srv) {
05380 return -1;
05381 }
05382
05383 if (! srv->no_nt_session) {
05384 ipc_srv = smbc_attr_server(context, server, share,
05385 workgroup, user, password,
05386 &pol);
05387 if (! ipc_srv) {
05388 srv->no_nt_session = True;
05389 }
05390 } else {
05391 ipc_srv = NULL;
05392 }
05393
05394 ctx = talloc_init("smbc_setxattr");
05395 if (!ctx) {
05396 errno = ENOMEM;
05397 return -1;
05398 }
05399
05400
05401
05402
05403 if (StrCaseCmp(name, "system.*") == 0 ||
05404 StrCaseCmp(name, "system.*+") == 0) {
05405
05406 char *namevalue =
05407 talloc_asprintf(ctx, "%s:%s",
05408 name+7, (const char *) value);
05409 if (! namevalue) {
05410 errno = ENOMEM;
05411 ret = -1;
05412 return -1;
05413 }
05414
05415 if (ipc_srv) {
05416 ret = cacl_set(ctx, srv->cli,
05417 ipc_srv->cli, &pol, path,
05418 namevalue,
05419 (*namevalue == '*'
05420 ? SMBC_XATTR_MODE_SET
05421 : SMBC_XATTR_MODE_ADD),
05422 flags);
05423 } else {
05424 ret = 0;
05425 }
05426
05427
05428 dad = dos_attr_query(context, ctx, path, srv);
05429 if (dad) {
05430
05431 dos_attr_parse(context, dad, srv, namevalue);
05432
05433
05434 if (! smbc_setatr(context, srv, path,
05435 dad->create_time,
05436 dad->access_time,
05437 dad->write_time,
05438 dad->change_time,
05439 dad->mode)) {
05440
05441
05442 dad = NULL;
05443 }
05444 }
05445
05446
05447 if (ret < 0 && ! dad) {
05448 ret = -1;
05449 }
05450 else {
05451 ret = 0;
05452 }
05453
05454 talloc_destroy(ctx);
05455 return ret;
05456 }
05457
05458
05459
05460
05461
05462 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
05463 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
05464 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
05465 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
05466 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
05467
05468
05469 char *namevalue =
05470 talloc_asprintf(ctx, "%s:%s",
05471 name+19, (const char *) value);
05472
05473 if (! ipc_srv) {
05474 ret = -1;
05475 }
05476 else if (! namevalue) {
05477 errno = ENOMEM;
05478 ret = -1;
05479 } else {
05480 ret = cacl_set(ctx, srv->cli,
05481 ipc_srv->cli, &pol, path,
05482 namevalue,
05483 (*namevalue == '*'
05484 ? SMBC_XATTR_MODE_SET
05485 : SMBC_XATTR_MODE_ADD),
05486 flags);
05487 }
05488 talloc_destroy(ctx);
05489 return ret;
05490 }
05491
05492
05493
05494
05495 if (StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
05496 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0) {
05497
05498
05499 char *namevalue =
05500 talloc_asprintf(ctx, "%s:%s",
05501 name+19, (const char *) value);
05502
05503 if (! ipc_srv) {
05504
05505 ret = -1;
05506 }
05507 else if (! namevalue) {
05508 errno = ENOMEM;
05509 ret = -1;
05510 } else {
05511 ret = cacl_set(ctx, srv->cli,
05512 ipc_srv->cli, &pol, path,
05513 namevalue, SMBC_XATTR_MODE_CHOWN, 0);
05514 }
05515 talloc_destroy(ctx);
05516 return ret;
05517 }
05518
05519
05520
05521
05522 if (StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
05523 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0) {
05524
05525
05526 char *namevalue =
05527 talloc_asprintf(ctx, "%s:%s",
05528 name+19, (const char *) value);
05529
05530 if (! ipc_srv) {
05531
05532 ret = -1;
05533 }
05534 else if (! namevalue) {
05535 errno = ENOMEM;
05536 ret = -1;
05537 } else {
05538 ret = cacl_set(ctx, srv->cli,
05539 ipc_srv->cli, &pol, path,
05540 namevalue, SMBC_XATTR_MODE_CHOWN, 0);
05541 }
05542 talloc_destroy(ctx);
05543 return ret;
05544 }
05545
05546
05547 if (context->internal->_full_time_names) {
05548
05549 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
05550 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
05551 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
05552 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
05553 } else {
05554
05555 attr_strings.create_time_attr = NULL;
05556 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
05557 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
05558 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
05559 }
05560
05561
05562
05563
05564 if (StrCaseCmp(name, "system.dos_attr.*") == 0 ||
05565 StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
05566 (attr_strings.create_time_attr != NULL &&
05567 StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
05568 StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
05569 StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
05570 StrCaseCmp(name, attr_strings.change_time_attr) == 0) {
05571
05572
05573 dad = dos_attr_query(context, ctx, path, srv);
05574 if (dad) {
05575 char *namevalue =
05576 talloc_asprintf(ctx, "%s:%s",
05577 name+16, (const char *) value);
05578 if (! namevalue) {
05579 errno = ENOMEM;
05580 ret = -1;
05581 } else {
05582
05583 dos_attr_parse(context, dad, srv, namevalue);
05584
05585
05586 ret2 = smbc_setatr(context, srv, path,
05587 dad->create_time,
05588 dad->access_time,
05589 dad->write_time,
05590 dad->change_time,
05591 dad->mode);
05592
05593
05594 if (ret2) {
05595 ret = 0;
05596 } else {
05597 ret = -1;
05598 }
05599 }
05600 } else {
05601 ret = -1;
05602 }
05603
05604 talloc_destroy(ctx);
05605 return ret;
05606 }
05607
05608
05609 talloc_destroy(ctx);
05610 errno = EINVAL;
05611 return -1;
05612 }
05613
05614 static int
05615 smbc_getxattr_ctx(SMBCCTX *context,
05616 const char *fname,
05617 const char *name,
05618 const void *value,
05619 size_t size)
05620 {
05621 int ret;
05622 SMBCSRV *srv;
05623 SMBCSRV *ipc_srv;
05624 fstring server;
05625 fstring share;
05626 fstring user;
05627 fstring password;
05628 fstring workgroup;
05629 pstring path;
05630 TALLOC_CTX *ctx;
05631 POLICY_HND pol;
05632 struct {
05633 const char * create_time_attr;
05634 const char * access_time_attr;
05635 const char * write_time_attr;
05636 const char * change_time_attr;
05637 } attr_strings;
05638
05639
05640 if (!context || !context->internal ||
05641 !context->internal->_initialized) {
05642
05643 errno = EINVAL;
05644 return -1;
05645
05646 }
05647
05648 if (!fname) {
05649
05650 errno = EINVAL;
05651 return -1;
05652
05653 }
05654
05655 DEBUG(4, ("smbc_getxattr(%s, %s)\n", fname, name));
05656
05657 if (smbc_parse_path(context, fname,
05658 workgroup, sizeof(workgroup),
05659 server, sizeof(server),
05660 share, sizeof(share),
05661 path, sizeof(path),
05662 user, sizeof(user),
05663 password, sizeof(password),
05664 NULL, 0)) {
05665 errno = EINVAL;
05666 return -1;
05667 }
05668
05669 if (user[0] == (char)0) fstrcpy(user, context->user);
05670
05671 srv = smbc_server(context, True,
05672 server, share, workgroup, user, password);
05673 if (!srv) {
05674 return -1;
05675 }
05676
05677 if (! srv->no_nt_session) {
05678 ipc_srv = smbc_attr_server(context, server, share,
05679 workgroup, user, password,
05680 &pol);
05681 if (! ipc_srv) {
05682 srv->no_nt_session = True;
05683 }
05684 } else {
05685 ipc_srv = NULL;
05686 }
05687
05688 ctx = talloc_init("smbc:getxattr");
05689 if (!ctx) {
05690 errno = ENOMEM;
05691 return -1;
05692 }
05693
05694
05695 if (context->internal->_full_time_names) {
05696
05697 attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME";
05698 attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME";
05699 attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME";
05700 attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME";
05701 } else {
05702
05703 attr_strings.create_time_attr = NULL;
05704 attr_strings.access_time_attr = "system.dos_attr.A_TIME";
05705 attr_strings.write_time_attr = "system.dos_attr.M_TIME";
05706 attr_strings.change_time_attr = "system.dos_attr.C_TIME";
05707 }
05708
05709
05710 if (StrCaseCmp(name, "system.*") == 0 ||
05711 StrnCaseCmp(name, "system.*!", 9) == 0 ||
05712 StrCaseCmp(name, "system.*+") == 0 ||
05713 StrnCaseCmp(name, "system.*+!", 10) == 0 ||
05714 StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
05715 StrnCaseCmp(name, "system.nt_sec_desc.*!", 21) == 0 ||
05716 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0 ||
05717 StrnCaseCmp(name, "system.nt_sec_desc.*+!", 22) == 0 ||
05718 StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
05719 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
05720 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
05721 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
05722 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
05723 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
05724 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0 ||
05725 StrCaseCmp(name, "system.dos_attr.*") == 0 ||
05726 StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 ||
05727 StrCaseCmp(name, "system.dos_attr.mode") == 0 ||
05728 StrCaseCmp(name, "system.dos_attr.size") == 0 ||
05729 (attr_strings.create_time_attr != NULL &&
05730 StrCaseCmp(name, attr_strings.create_time_attr) == 0) ||
05731 StrCaseCmp(name, attr_strings.access_time_attr) == 0 ||
05732 StrCaseCmp(name, attr_strings.write_time_attr) == 0 ||
05733 StrCaseCmp(name, attr_strings.change_time_attr) == 0 ||
05734 StrCaseCmp(name, "system.dos_attr.inode") == 0) {
05735
05736
05737 ret = cacl_get(context, ctx, srv,
05738 ipc_srv == NULL ? NULL : ipc_srv->cli,
05739 &pol, path,
05740 CONST_DISCARD(char *, name),
05741 CONST_DISCARD(char *, value), size);
05742 if (ret < 0 && errno == 0) {
05743 errno = smbc_errno(context, srv->cli);
05744 }
05745 talloc_destroy(ctx);
05746 return ret;
05747 }
05748
05749
05750 talloc_destroy(ctx);
05751 errno = EINVAL;
05752 return -1;
05753 }
05754
05755
05756 static int
05757 smbc_removexattr_ctx(SMBCCTX *context,
05758 const char *fname,
05759 const char *name)
05760 {
05761 int ret;
05762 SMBCSRV *srv;
05763 SMBCSRV *ipc_srv;
05764 fstring server;
05765 fstring share;
05766 fstring user;
05767 fstring password;
05768 fstring workgroup;
05769 pstring path;
05770 TALLOC_CTX *ctx;
05771 POLICY_HND pol;
05772
05773 if (!context || !context->internal ||
05774 !context->internal->_initialized) {
05775
05776 errno = EINVAL;
05777 return -1;
05778
05779 }
05780
05781 if (!fname) {
05782
05783 errno = EINVAL;
05784 return -1;
05785
05786 }
05787
05788 DEBUG(4, ("smbc_removexattr(%s, %s)\n", fname, name));
05789
05790 if (smbc_parse_path(context, fname,
05791 workgroup, sizeof(workgroup),
05792 server, sizeof(server),
05793 share, sizeof(share),
05794 path, sizeof(path),
05795 user, sizeof(user),
05796 password, sizeof(password),
05797 NULL, 0)) {
05798 errno = EINVAL;
05799 return -1;
05800 }
05801
05802 if (user[0] == (char)0) fstrcpy(user, context->user);
05803
05804 srv = smbc_server(context, True,
05805 server, share, workgroup, user, password);
05806 if (!srv) {
05807 return -1;
05808 }
05809
05810 if (! srv->no_nt_session) {
05811 ipc_srv = smbc_attr_server(context, server, share,
05812 workgroup, user, password,
05813 &pol);
05814 if (! ipc_srv) {
05815 srv->no_nt_session = True;
05816 }
05817 } else {
05818 ipc_srv = NULL;
05819 }
05820
05821 if (! ipc_srv) {
05822 return -1;
05823 }
05824
05825 ctx = talloc_init("smbc_removexattr");
05826 if (!ctx) {
05827 errno = ENOMEM;
05828 return -1;
05829 }
05830
05831
05832 if (StrCaseCmp(name, "system.nt_sec_desc.*") == 0 ||
05833 StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) {
05834
05835
05836 ret = cacl_set(ctx, srv->cli,
05837 ipc_srv->cli, &pol, path,
05838 NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0);
05839 talloc_destroy(ctx);
05840 return ret;
05841 }
05842
05843
05844
05845
05846
05847 if (StrCaseCmp(name, "system.nt_sec_desc.revision") == 0 ||
05848 StrCaseCmp(name, "system.nt_sec_desc.owner") == 0 ||
05849 StrCaseCmp(name, "system.nt_sec_desc.owner+") == 0 ||
05850 StrCaseCmp(name, "system.nt_sec_desc.group") == 0 ||
05851 StrCaseCmp(name, "system.nt_sec_desc.group+") == 0 ||
05852 StrnCaseCmp(name, "system.nt_sec_desc.acl", 22) == 0 ||
05853 StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) {
05854
05855
05856 ret = cacl_set(ctx, srv->cli,
05857 ipc_srv->cli, &pol, path,
05858 name + 19, SMBC_XATTR_MODE_REMOVE, 0);
05859 talloc_destroy(ctx);
05860 return ret;
05861 }
05862
05863
05864 talloc_destroy(ctx);
05865 errno = EINVAL;
05866 return -1;
05867 }
05868
05869 static int
05870 smbc_listxattr_ctx(SMBCCTX *context,
05871 const char *fname,
05872 char *list,
05873 size_t size)
05874 {
05875
05876
05877
05878
05879
05880 const char supported_old[] =
05881 "system.*\0"
05882 "system.*+\0"
05883 "system.nt_sec_desc.revision\0"
05884 "system.nt_sec_desc.owner\0"
05885 "system.nt_sec_desc.owner+\0"
05886 "system.nt_sec_desc.group\0"
05887 "system.nt_sec_desc.group+\0"
05888 "system.nt_sec_desc.acl.*\0"
05889 "system.nt_sec_desc.acl\0"
05890 "system.nt_sec_desc.acl+\0"
05891 "system.nt_sec_desc.*\0"
05892 "system.nt_sec_desc.*+\0"
05893 "system.dos_attr.*\0"
05894 "system.dos_attr.mode\0"
05895 "system.dos_attr.c_time\0"
05896 "system.dos_attr.a_time\0"
05897 "system.dos_attr.m_time\0"
05898 ;
05899 const char supported_new[] =
05900 "system.*\0"
05901 "system.*+\0"
05902 "system.nt_sec_desc.revision\0"
05903 "system.nt_sec_desc.owner\0"
05904 "system.nt_sec_desc.owner+\0"
05905 "system.nt_sec_desc.group\0"
05906 "system.nt_sec_desc.group+\0"
05907 "system.nt_sec_desc.acl.*\0"
05908 "system.nt_sec_desc.acl\0"
05909 "system.nt_sec_desc.acl+\0"
05910 "system.nt_sec_desc.*\0"
05911 "system.nt_sec_desc.*+\0"
05912 "system.dos_attr.*\0"
05913 "system.dos_attr.mode\0"
05914 "system.dos_attr.create_time\0"
05915 "system.dos_attr.access_time\0"
05916 "system.dos_attr.write_time\0"
05917 "system.dos_attr.change_time\0"
05918 ;
05919 const char * supported;
05920
05921 if (context->internal->_full_time_names) {
05922 supported = supported_new;
05923 } else {
05924 supported = supported_old;
05925 }
05926
05927 if (size == 0) {
05928 return sizeof(supported);
05929 }
05930
05931 if (sizeof(supported) > size) {
05932 errno = ERANGE;
05933 return -1;
05934 }
05935
05936
05937 memcpy(list, supported, sizeof(supported));
05938 return sizeof(supported);
05939 }
05940
05941
05942
05943
05944
05945
05946 static SMBCFILE *
05947 smbc_open_print_job_ctx(SMBCCTX *context,
05948 const char *fname)
05949 {
05950 fstring server;
05951 fstring share;
05952 fstring user;
05953 fstring password;
05954 pstring path;
05955
05956 if (!context || !context->internal ||
05957 !context->internal->_initialized) {
05958
05959 errno = EINVAL;
05960 return NULL;
05961
05962 }
05963
05964 if (!fname) {
05965
05966 errno = EINVAL;
05967 return NULL;
05968
05969 }
05970
05971 DEBUG(4, ("smbc_open_print_job_ctx(%s)\n", fname));
05972
05973 if (smbc_parse_path(context, fname,
05974 NULL, 0,
05975 server, sizeof(server),
05976 share, sizeof(share),
05977 path, sizeof(path),
05978 user, sizeof(user),
05979 password, sizeof(password),
05980 NULL, 0)) {
05981 errno = EINVAL;
05982 return NULL;
05983 }
05984
05985
05986
05987 return (context->open)(context, fname, O_WRONLY, 666);
05988
05989 }
05990
05991
05992
05993
05994
05995
05996
05997
05998 static int
05999 smbc_print_file_ctx(SMBCCTX *c_file,
06000 const char *fname,
06001 SMBCCTX *c_print,
06002 const char *printq)
06003 {
06004 SMBCFILE *fid1;
06005 SMBCFILE *fid2;
06006 int bytes;
06007 int saverr;
06008 int tot_bytes = 0;
06009 char buf[4096];
06010
06011 if (!c_file || !c_file->internal->_initialized || !c_print ||
06012 !c_print->internal->_initialized) {
06013
06014 errno = EINVAL;
06015 return -1;
06016
06017 }
06018
06019 if (!fname && !printq) {
06020
06021 errno = EINVAL;
06022 return -1;
06023
06024 }
06025
06026
06027
06028 if ((long)(fid1 = (c_file->open)(c_file, fname, O_RDONLY, 0666)) < 0) {
06029
06030 DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
06031 return -1;
06032
06033 }
06034
06035
06036
06037 if ((long)(fid2 = (c_print->open_print_job)(c_print, printq)) < 0) {
06038
06039 saverr = errno;
06040 (c_file->close_fn)(c_file, fid1);
06041 errno = saverr;
06042 return -1;
06043
06044 }
06045
06046 while ((bytes = (c_file->read)(c_file, fid1, buf, sizeof(buf))) > 0) {
06047
06048 tot_bytes += bytes;
06049
06050 if (((c_print->write)(c_print, fid2, buf, bytes)) < 0) {
06051
06052 saverr = errno;
06053 (c_file->close_fn)(c_file, fid1);
06054 (c_print->close_fn)(c_print, fid2);
06055 errno = saverr;
06056
06057 }
06058
06059 }
06060
06061 saverr = errno;
06062
06063 (c_file->close_fn)(c_file, fid1);
06064 (c_print->close_fn)(c_print, fid2);
06065
06066 if (bytes < 0) {
06067
06068 errno = saverr;
06069 return -1;
06070
06071 }
06072
06073 return tot_bytes;
06074
06075 }
06076
06077
06078
06079
06080
06081 static int
06082 smbc_list_print_jobs_ctx(SMBCCTX *context,
06083 const char *fname,
06084 smbc_list_print_job_fn fn)
06085 {
06086 SMBCSRV *srv;
06087 fstring server;
06088 fstring share;
06089 fstring user;
06090 fstring password;
06091 fstring workgroup;
06092 pstring path;
06093
06094 if (!context || !context->internal ||
06095 !context->internal->_initialized) {
06096
06097 errno = EINVAL;
06098 return -1;
06099
06100 }
06101
06102 if (!fname) {
06103
06104 errno = EINVAL;
06105 return -1;
06106
06107 }
06108
06109 DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
06110
06111 if (smbc_parse_path(context, fname,
06112 workgroup, sizeof(workgroup),
06113 server, sizeof(server),
06114 share, sizeof(share),
06115 path, sizeof(path),
06116 user, sizeof(user),
06117 password, sizeof(password),
06118 NULL, 0)) {
06119 errno = EINVAL;
06120 return -1;
06121 }
06122
06123 if (user[0] == (char)0) fstrcpy(user, context->user);
06124
06125 srv = smbc_server(context, True,
06126 server, share, workgroup, user, password);
06127
06128 if (!srv) {
06129
06130 return -1;
06131
06132 }
06133
06134 if (cli_print_queue(srv->cli,
06135 (void (*)(struct print_job_info *))fn) < 0) {
06136
06137 errno = smbc_errno(context, srv->cli);
06138 return -1;
06139
06140 }
06141
06142 return 0;
06143
06144 }
06145
06146
06147
06148
06149
06150 static int
06151 smbc_unlink_print_job_ctx(SMBCCTX *context,
06152 const char *fname,
06153 int id)
06154 {
06155 SMBCSRV *srv;
06156 fstring server;
06157 fstring share;
06158 fstring user;
06159 fstring password;
06160 fstring workgroup;
06161 pstring path;
06162 int err;
06163
06164 if (!context || !context->internal ||
06165 !context->internal->_initialized) {
06166
06167 errno = EINVAL;
06168 return -1;
06169
06170 }
06171
06172 if (!fname) {
06173
06174 errno = EINVAL;
06175 return -1;
06176
06177 }
06178
06179 DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
06180
06181 if (smbc_parse_path(context, fname,
06182 workgroup, sizeof(workgroup),
06183 server, sizeof(server),
06184 share, sizeof(share),
06185 path, sizeof(path),
06186 user, sizeof(user),
06187 password, sizeof(password),
06188 NULL, 0)) {
06189 errno = EINVAL;
06190 return -1;
06191 }
06192
06193 if (user[0] == (char)0) fstrcpy(user, context->user);
06194
06195 srv = smbc_server(context, True,
06196 server, share, workgroup, user, password);
06197
06198 if (!srv) {
06199
06200 return -1;
06201
06202 }
06203
06204 if ((err = cli_printjob_del(srv->cli, id)) != 0) {
06205
06206 if (err < 0)
06207 errno = smbc_errno(context, srv->cli);
06208 else if (err == ERRnosuchprintjob)
06209 errno = EINVAL;
06210 return -1;
06211
06212 }
06213
06214 return 0;
06215
06216 }
06217
06218
06219
06220
06221 SMBCCTX *
06222 smbc_new_context(void)
06223 {
06224 SMBCCTX *context;
06225
06226 context = SMB_MALLOC_P(SMBCCTX);
06227 if (!context) {
06228 errno = ENOMEM;
06229 return NULL;
06230 }
06231
06232 ZERO_STRUCTP(context);
06233
06234 context->internal = SMB_MALLOC_P(struct smbc_internal_data);
06235 if (!context->internal) {
06236 SAFE_FREE(context);
06237 errno = ENOMEM;
06238 return NULL;
06239 }
06240
06241 ZERO_STRUCTP(context->internal);
06242
06243
06244
06245 context->debug = 0;
06246 context->timeout = 20000;
06247
06248 context->options.browse_max_lmb_count = 3;
06249 context->options.urlencode_readdir_entries = False;
06250 context->options.one_share_per_server = False;
06251 context->internal->_share_mode = SMBC_SHAREMODE_DENY_NONE;
06252
06253
06254 context->open = smbc_open_ctx;
06255 context->creat = smbc_creat_ctx;
06256 context->read = smbc_read_ctx;
06257 context->write = smbc_write_ctx;
06258 context->close_fn = smbc_close_ctx;
06259 context->unlink = smbc_unlink_ctx;
06260 context->rename = smbc_rename_ctx;
06261 context->lseek = smbc_lseek_ctx;
06262 context->stat = smbc_stat_ctx;
06263 context->fstat = smbc_fstat_ctx;
06264 context->opendir = smbc_opendir_ctx;
06265 context->closedir = smbc_closedir_ctx;
06266 context->readdir = smbc_readdir_ctx;
06267 context->getdents = smbc_getdents_ctx;
06268 context->mkdir = smbc_mkdir_ctx;
06269 context->rmdir = smbc_rmdir_ctx;
06270 context->telldir = smbc_telldir_ctx;
06271 context->lseekdir = smbc_lseekdir_ctx;
06272 context->fstatdir = smbc_fstatdir_ctx;
06273 context->chmod = smbc_chmod_ctx;
06274 context->utimes = smbc_utimes_ctx;
06275 context->setxattr = smbc_setxattr_ctx;
06276 context->getxattr = smbc_getxattr_ctx;
06277 context->removexattr = smbc_removexattr_ctx;
06278 context->listxattr = smbc_listxattr_ctx;
06279 context->open_print_job = smbc_open_print_job_ctx;
06280 context->print_file = smbc_print_file_ctx;
06281 context->list_print_jobs = smbc_list_print_jobs_ctx;
06282 context->unlink_print_job = smbc_unlink_print_job_ctx;
06283
06284 context->callbacks.check_server_fn = smbc_check_server;
06285 context->callbacks.remove_unused_server_fn = smbc_remove_unused_server;
06286
06287 smbc_default_cache_functions(context);
06288
06289 return context;
06290 }
06291
06292
06293
06294
06295
06296
06297
06298
06299 int
06300 smbc_free_context(SMBCCTX *context,
06301 int shutdown_ctx)
06302 {
06303 if (!context) {
06304 errno = EBADF;
06305 return 1;
06306 }
06307
06308 if (shutdown_ctx) {
06309 SMBCFILE * f;
06310 DEBUG(1,("Performing aggressive shutdown.\n"));
06311
06312 f = context->internal->_files;
06313 while (f) {
06314 (context->close_fn)(context, f);
06315 f = f->next;
06316 }
06317 context->internal->_files = NULL;
06318
06319
06320 if (context->callbacks.purge_cached_fn(context)) {
06321 SMBCSRV * s;
06322 SMBCSRV * next;
06323 DEBUG(1, ("Could not purge all servers, "
06324 "Nice way shutdown failed.\n"));
06325 s = context->internal->_servers;
06326 while (s) {
06327 DEBUG(1, ("Forced shutdown: %p (fd=%d)\n",
06328 s, s->cli->fd));
06329 cli_shutdown(s->cli);
06330 (context->callbacks.remove_cached_srv_fn)(context,
06331 s);
06332 next = s->next;
06333 DLIST_REMOVE(context->internal->_servers, s);
06334 SAFE_FREE(s);
06335 s = next;
06336 }
06337 context->internal->_servers = NULL;
06338 }
06339 }
06340 else {
06341
06342 if ((context->callbacks.purge_cached_fn)(context)) {
06343 DEBUG(1, ("Could not purge all servers, "
06344 "free_context failed.\n"));
06345 errno = EBUSY;
06346 return 1;
06347 }
06348 if (context->internal->_servers) {
06349 DEBUG(1, ("Active servers in context, "
06350 "free_context failed.\n"));
06351 errno = EBUSY;
06352 return 1;
06353 }
06354 if (context->internal->_files) {
06355 DEBUG(1, ("Active files in context, "
06356 "free_context failed.\n"));
06357 errno = EBUSY;
06358 return 1;
06359 }
06360 }
06361
06362
06363 SAFE_FREE(context->workgroup);
06364 SAFE_FREE(context->netbios_name);
06365 SAFE_FREE(context->user);
06366
06367 DEBUG(3, ("Context %p successfully freed\n", context));
06368 SAFE_FREE(context->internal);
06369 SAFE_FREE(context);
06370 return 0;
06371 }
06372
06373
06374
06375
06376
06377
06378
06379
06380
06381 void
06382 smbc_option_set(SMBCCTX *context,
06383 char *option_name,
06384 ... )
06385 {
06386 va_list ap;
06387 union {
06388 int i;
06389 BOOL b;
06390 smbc_get_auth_data_with_context_fn auth_fn;
06391 void *v;
06392 } option_value;
06393
06394 va_start(ap, option_name);
06395
06396 if (strcmp(option_name, "debug_to_stderr") == 0) {
06397
06398
06399
06400 option_value.b = (BOOL) va_arg(ap, int);
06401 context->internal->_debug_stderr = option_value.b;
06402
06403 } else if (strcmp(option_name, "full_time_names") == 0) {
06404
06405
06406
06407
06408
06409
06410
06411
06412 option_value.b = (BOOL) va_arg(ap, int);
06413 context->internal->_full_time_names = option_value.b;
06414
06415 } else if (strcmp(option_name, "open_share_mode") == 0) {
06416
06417
06418
06419
06420 option_value.i = va_arg(ap, int);
06421 context->internal->_share_mode =
06422 (smbc_share_mode) option_value.i;
06423
06424 } else if (strcmp(option_name, "auth_function") == 0) {
06425
06426
06427
06428
06429 option_value.auth_fn =
06430 va_arg(ap, smbc_get_auth_data_with_context_fn);
06431 context->internal->_auth_fn_with_context =
06432 option_value.auth_fn;
06433 } else if (strcmp(option_name, "user_data") == 0) {
06434
06435
06436
06437
06438 option_value.v = va_arg(ap, void *);
06439 context->internal->_user_data = option_value.v;
06440 }
06441
06442 va_end(ap);
06443 }
06444
06445
06446
06447
06448
06449 void *
06450 smbc_option_get(SMBCCTX *context,
06451 char *option_name)
06452 {
06453 if (strcmp(option_name, "debug_stderr") == 0) {
06454
06455
06456
06457 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
06458 return (void *) (intptr_t) context->internal->_debug_stderr;
06459 #else
06460 return (void *) context->internal->_debug_stderr;
06461 #endif
06462 } else if (strcmp(option_name, "full_time_names") == 0) {
06463
06464
06465
06466
06467
06468
06469
06470
06471 #if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T)
06472 return (void *) (intptr_t) context->internal->_full_time_names;
06473 #else
06474 return (void *) context->internal->_full_time_names;
06475 #endif
06476
06477 } else if (strcmp(option_name, "auth_function") == 0) {
06478
06479
06480
06481
06482 return (void *) context->internal->_auth_fn_with_context;
06483 } else if (strcmp(option_name, "user_data") == 0) {
06484
06485
06486
06487
06488 return context->internal->_user_data;
06489 }
06490
06491 return NULL;
06492 }
06493
06494
06495
06496
06497
06498
06499
06500
06501
06502 SMBCCTX *
06503 smbc_init_context(SMBCCTX *context)
06504 {
06505 pstring conf;
06506 int pid;
06507 char *user = NULL;
06508 char *home = NULL;
06509
06510 if (!context || !context->internal) {
06511 errno = EBADF;
06512 return NULL;
06513 }
06514
06515
06516 if (context->internal->_initialized) {
06517 return 0;
06518 }
06519
06520 if ((!context->callbacks.auth_fn &&
06521 !context->internal->_auth_fn_with_context) ||
06522 context->debug < 0 ||
06523 context->debug > 100) {
06524
06525 errno = EINVAL;
06526 return NULL;
06527
06528 }
06529
06530 if (!smbc_initialized) {
06531
06532
06533
06534
06535 BOOL conf_loaded = False;
06536
06537
06538 DEBUGLEVEL = context->debug;
06539
06540 load_case_tables();
06541
06542 setup_logging("libsmbclient", True);
06543 if (context->internal->_debug_stderr) {
06544 dbf = x_stderr;
06545 x_setbuf(x_stderr, NULL);
06546 }
06547
06548
06549
06550 in_client = True;
06551
06552 home = getenv("HOME");
06553 if (home) {
06554 slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
06555 if (lp_load(conf, True, False, False, True)) {
06556 conf_loaded = True;
06557 } else {
06558 DEBUG(5, ("Could not load config file: %s\n",
06559 conf));
06560 }
06561 }
06562
06563 if (!conf_loaded) {
06564
06565
06566
06567
06568
06569
06570
06571 if (!lp_load(dyn_CONFIGFILE, True, False, False, False)) {
06572 DEBUG(5, ("Could not load config file: %s\n",
06573 dyn_CONFIGFILE));
06574 } else if (home) {
06575
06576
06577
06578
06579
06580 slprintf(conf, sizeof(conf),
06581 "%s/.smb/smb.conf.append", home);
06582 if (!lp_load(conf, True, False, False, False)) {
06583 DEBUG(10,
06584 ("Could not append config file: "
06585 "%s\n",
06586 conf));
06587 }
06588 }
06589 }
06590
06591 load_interfaces();
06592
06593 reopen_logs();
06594
06595
06596
06597
06598
06599 BlockSignals(True, SIGPIPE);
06600
06601
06602 smbc_initialized = 1;
06603
06604 }
06605
06606 if (!context->user) {
06607
06608
06609
06610 user = getenv("USER");
06611
06612 if (!user) context->user = SMB_STRDUP("guest");
06613 else context->user = SMB_STRDUP(user);
06614 }
06615
06616 if (!context->netbios_name) {
06617
06618
06619
06620
06621
06622 if (global_myname()) {
06623 context->netbios_name = SMB_STRDUP(global_myname());
06624 }
06625 else {
06626
06627
06628
06629
06630 pid = sys_getpid();
06631 context->netbios_name = (char *)SMB_MALLOC(17);
06632 if (!context->netbios_name) {
06633 errno = ENOMEM;
06634 return NULL;
06635 }
06636 slprintf(context->netbios_name, 16,
06637 "smbc%s%d", context->user, pid);
06638 }
06639 }
06640
06641 DEBUG(1, ("Using netbios name %s.\n", context->netbios_name));
06642
06643 if (!context->workgroup) {
06644 if (lp_workgroup()) {
06645 context->workgroup = SMB_STRDUP(lp_workgroup());
06646 }
06647 else {
06648
06649 context->workgroup = SMB_STRDUP("samba");
06650 }
06651 }
06652
06653 DEBUG(1, ("Using workgroup %s.\n", context->workgroup));
06654
06655
06656 if (context->timeout > 0 && context->timeout < 1000)
06657 context->timeout = 1000;
06658
06659
06660
06661
06662
06663 context->internal->_initialized = True;
06664
06665 return context;
06666 }
06667
06668
06669
06670 const char *
06671 smbc_version(void)
06672 {
06673 return samba_version_string();
06674 }